package com.ssy.lingxi.order.serviceimpl.base;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.ssy.lingxi.common.constant.marketing.ActivityTypeEnum;
import com.ssy.lingxi.common.constant.marketing.BelongTypeEnum;
import com.ssy.lingxi.common.constant.marketing.MerchantCouponTypeEnum;
import com.ssy.lingxi.common.constant.marketing.PlatformCouponTypeEnum;
import com.ssy.lingxi.common.constant.order.OrderSourceKindEnum;
import com.ssy.lingxi.common.constant.product.PriceTypeEnum;
import com.ssy.lingxi.common.model.dto.MemberAndRoleIdDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.order.api.model.vo.response.OrderFreeExpressConfigVO;
import com.ssy.lingxi.order.entity.OrderDO;
import com.ssy.lingxi.order.entity.OrderGiveCouponDO;
import com.ssy.lingxi.order.entity.OrderMaterialDO;
import com.ssy.lingxi.order.entity.OrderProductDO;
import com.ssy.lingxi.order.model.bo.*;
import com.ssy.lingxi.order.model.constant.*;
import com.ssy.lingxi.order.model.dto.*;
import com.ssy.lingxi.order.model.vo.basic.request.*;
import com.ssy.lingxi.order.model.vo.basic.response.OrderDeliverySummaryVO;
import com.ssy.lingxi.order.model.vo.basic.response.OrderProductDetailVO;
import com.ssy.lingxi.order.model.vo.basic.response.OrderProductSummaryVO;
import com.ssy.lingxi.order.model.vo.mobile.request.BuyerOrderVO;
import com.ssy.lingxi.order.model.vo.vendor.request.AgentPurchaseOrderVO;
import com.ssy.lingxi.order.model.vo.vendor.request.VendorDeliveryVO;
import com.ssy.lingxi.order.model.vo.vendor.request.VendorToDeliveryProductVO;
import com.ssy.lingxi.order.model.vo.vendor.request.VendorUpdateProductPriceVO;
import com.ssy.lingxi.order.model.vo.vendor.response.VendorDeliveryProductVO;
import com.ssy.lingxi.order.repository.OrderGiveCouponRepository;
import com.ssy.lingxi.order.repository.OrderProductRepository;
import com.ssy.lingxi.order.repository.OrderRepository;
import com.ssy.lingxi.order.service.base.IBaseOrderProductService;
import com.ssy.lingxi.order.service.base.IBaseOrderPromotionService;
import com.ssy.lingxi.order.service.feign.ILogisticsFeignService;
import com.ssy.lingxi.order.service.feign.IMarketingFeignService;
import com.ssy.lingxi.order.service.feign.IProductFeignService;
import com.ssy.lingxi.order.service.feign.ITradeFeignService;
import com.ssy.lingxi.order.service.web.IOrderParamConfigService;
import com.ssy.lingxi.order.utils.NumberUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 订单商品相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-07-18
 */
@Service
public class BaseOrderProductServiceImpl implements IBaseOrderProductService {

    private final static Logger logger = LoggerFactory.getLogger(BaseOrderProductServiceImpl.class);

    @Resource
    private IBaseOrderPromotionService baseOrderPromotionService;

    @Resource
    private OrderRepository orderRepository;

    @Resource
    private OrderProductRepository orderProductRepository;

    @Resource
    private IProductFeignService productFeignService;
    
    @Resource
    private IMarketingFeignService marketingFeignService;

    @Resource
    private ILogisticsFeignService logisticsFeignService;

    @Resource
    private ITradeFeignService tradeFeignService;

    @Resource
    private IOrderParamConfigService orderParamConfigService;


    @Resource
    private OrderGiveCouponRepository orderGiveCouponRepository;

    /**
     * 批量查询订单商品列表
     *
     * @param orders 订单列表
     * @return 订单商品列表
     */
    @Override
    public List<OrderProductDO> findByOrderIn(List<OrderDO> orders) {
        return orderProductRepository.findByOrderIn(orders);
    }

    /**
     * 校验商品价格、运费
     *
     * @param buyerMemberId    采购会员Id
     * @param buyerRoleId      采购会员角色Id
     * @param memberType       登录用户的会员类型，以此判断采购商品是会员商品，还是渠道商品
     * @param shopId           前端商城Id
     * @param freight          前端传递的运费
     * @param vendorProductMap 供应商及其商品列表
     * @return 订单运费
     */
    @Override
    public Wrapper<BigDecimal> checkOrderProductPrices(Long buyerMemberId, Long buyerRoleId, Integer memberType, Long shopId, BigDecimal freight, Map<VendorBO, List<OrderProductVO>> vendorProductMap) {
        //多供应商时，所有商品的运费方式必须为“无运费”或“卖家承担”
        if(vendorProductMap.size() > 1 && vendorProductMap.values().stream().flatMap(products -> products.stream().map(product -> NumberUtil.isNullOrNegative(product.getFreightType()) ? OrderFreightTypeEnum.VENDOR.getCode() : product.getFreightType())).anyMatch(freightType -> !freightType.equals(OrderFreightTypeEnum.VENDOR.getCode()))) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_FREIGHT_TYPE_MUST_BE_VENDOR);
        }

        for (Map.Entry<VendorBO, List<OrderProductVO>> entry : vendorProductMap.entrySet()) {
            //从商品服务获得商品阶梯价格
//            Wrapper<Map<Long, Map<String, Double>>> priceResult = productFeignService.batchCheckProductPrice(buyerMemberId, buyerRoleId, shopId, memberType, entry.getValue().stream().map(OrderProductVO::getSkuId).collect(Collectors.toList()));
//            if(priceResult.getCode() != ResponseCode.SUCCESS.getCode()) {
//                return Wrapper.fail(priceResult.getCode(), priceResult.getMessage());
//            }

            // 校验商品价格
            for (OrderProductVO product : entry.getValue()) {
//                Map<String, Double> priceMap = priceResult.getData().get(product.getSkuId());
//                if(priceMap == null) {
//                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
//                }
//
//                Wrapper<Void> priceCheckResult = checkProductPrice(priceMap, product.getQuantity(), product.getPrice());
//                if(priceCheckResult.getCode() != ResponseCode.SUCCESS.getCode()) {
//                    return Wrapper.fail(priceCheckResult.getCode(), priceCheckResult.getMessage());
//                }

                //校验其他参数（需要判断运费模板Id）
                if(product.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode())) {
                    if(!StringUtils.hasText(product.getReceiver())) {
                        return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_IS_MISSING);
                    }

                    if(!StringUtils.hasText(product.getPhone())) {
                        return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_PHONE_IS_MISSING);
                    }

                    if(!StringUtils.hasText(product.getAddress())) {
                        return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_ADDRESS_IS_MISSING);
                    }
                }
            }
        }

        return Wrapper.success(vendorProductMap.size() == 1 ? freight : BigDecimal.ZERO);
    }

    /**
     * App - （商品、会员、物流、营销服务）查询商品详情、折扣、物流、促销活动等信息
     *
     * @param buyerMemberId        采购会员Id
     * @param buyerRoleId          采购会员角色Id
     * @param buyerMemberLevelType 采购会员（当前登录用户）等级类型
     * @param orderVO              订单接口参数
     * @param vendorCount          供应商数量
     * @param processPayment       交易流程是否需要支付
     * @param firstPayRate         交易流程中第一批次中最小支付次数的支付比例
     * @return 校验、修改接口参数中的商品到手价格
     */
    @Override
    public Wrapper<BuyerOrderCheckBO> checkMobileOrderProductPrices(Long buyerMemberId, Long buyerRoleId, Integer buyerMemberLevelType, BuyerOrderVO orderVO, int vendorCount, boolean processPayment, BigDecimal firstPayRate) {
        //****************************************************
        // Step 1： 接口参数、规则判断
        //****************************************************
        List<MobileOrderProductVO> orderProducts = orderVO.getProducts();
        // Step 1-1: 商品SkuId不能重复
        if(orderProducts.size() != orderProducts.stream().map(MobileOrderProductVO::getSkuId).distinct().count()) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_SKU_ID_DUPLICATED);
        }

        // Step 1-2 : 多供应商时，所有商品的运费方式必须为“无运费”或“卖家承担”
        if(vendorCount > 1 && orderProducts.stream().map(product -> NumberUtil.isNullOrNegative(product.getFreightType()) ? OrderFreightTypeEnum.VENDOR.getCode() : product.getFreightType()).anyMatch(freightType -> !freightType.equals(OrderFreightTypeEnum.VENDOR.getCode()))) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_FREIGHT_TYPE_MUST_BE_VENDOR);
        }

        // Step 1-3 : 到手价格：“普通商品”的到手价应该小于等于单价
        if(orderProducts.stream().filter(product -> NumberUtil.isNullOrZero(product.getPromotionType())).anyMatch(product -> product.getRefPrice().compareTo(product.getPrice()) > 0)) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_REF_PRICE_SHOULD_LTE_PRICE);
        }

        // Step 1-4 : 订单商品需要物流配送时，收货人信息不能为空
        if(orderProducts.stream().anyMatch(product -> product.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode())) && orderVO.getConsignee() == null) {
            return Wrapper.fail(ResponseCode.ORDER_CONSIGNEE_MUST_NOT_EMPTY);
        }

        // Step 1-4 : 检查订单接口参数：商品列表
        for (MobileOrderProductVO product : orderProducts) {
            //套餐主商品的套餐编号要大于0
            if(product.getPromotionType().equals(OrderPromotionTypeEnum.PRIMARY_OF_SET.getCode()) && NumberUtil.isNullOrNegativeZero(product.getGroupNo())) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_PRIMARY_OF_SET_GROUP_NO_SHOULD_GT_ZERO);
            }

            //如果是赠品，到手价要为0
            if(product.getPriceType().equals(PriceTypeEnum.Gift.getCode()) && product.getRefPrice().compareTo(BigDecimal.ZERO) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_GIFT_REF_PRICE_SHOULD_BE_ZERO);
            }

            //被换购商品的parentSkuId要大于0，并且存在于商品列表中
            if(product.getPromotionType().equals(OrderPromotionTypeEnum.EXCHANGED.getCode())) {
                if(NumberUtil.isNullOrNegativeZero(product.getParentSkuId())) {
                    return Wrapper.fail(ResponseCode.ORDER_EXCHANGED_PRODUCT_PARENT_SKU_ID_SHOULD_GT_ZERO);
                }

                if(orderVO.getProducts().stream().noneMatch(p -> p.getSkuId().equals(product.getParentSkuId()))) {
                    return Wrapper.fail(ResponseCode.ORDER_TO_EXCHANGED_PRODUCT_SKU_ID_SHOULD_INCLUDE_IN_PRODUCTS);
                }
            }

            //如果配送方式为“自提”，自提地址、联系人、电话不能为空
            if(product.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode()) && NumberUtil.isNullOrZero(product.getAddressId())) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_ADDRESS_ID_IS_MISSING);
            }

            //如果配送方式为“物流”，配送方式不能为空
            if(product.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode())) {
                if(NumberUtil.isNullOrZero(product.getFreightType())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_FREIGHT_TYPE_CAN_NOT_BE_NULL);
                }

                //如果运费类型为“买家承担”，物流模板Id、商品重量不能为空或0
                if(product.getFreightType().equals(OrderFreightTypeEnum.BUYER.getCode())) {
                    if(NumberUtil.isNullOrNegativeZero(product.getLogisticsTemplateId())) {
                        return Wrapper.fail(ResponseCode.ORDER_PRODUCT_LOGISTICS_TEMPLATE_ID_MUST_GREATER_THAN_ZERO);
                    }

                    if(NumberUtil.isNullOrNegativeZero(product.getWeight())) {
                        return Wrapper.fail(ResponseCode.ORDER_PRODUCT_WEIGHT_MUST_GREATER_THAN_ZERO);
                    }
                }
            }

            // 为方便后续校验，如果前端传Null值，将配送方式、自提地址Id，运费类型、营销活动列表设置为非Null值
            product.setDeliveryType(NumberUtil.isNullOrNegativeZero(product.getDeliveryType()) ? 0 : product.getDeliveryType());
            product.setAddressId(NumberUtil.isNullOrZero(product.getAddressId()) ? 0 : product.getAddressId());
            product.setFreightType(NumberUtil.isNullOrNegativeZero(product.getFreightType()) ? 0 : product.getFreightType());
            product.setPromotions(CollectionUtils.isEmpty(product.getPromotions()) ? new ArrayList<>() : product.getPromotions());
        }

        // 为方便后续校验，如果前端传Null值，将优惠券列表、积分抵扣列表、配送时间和备注设置成空列表
        orderVO.setCoupons(CollectionUtils.isEmpty(orderVO.getCoupons()) ? new ArrayList<>() : orderVO.getCoupons());
        orderVO.setDeductions(CollectionUtils.isEmpty(orderVO.getDeductions()) ? new ArrayList<>() : orderVO.getDeductions());
        orderVO.setDeliverTimes(CollectionUtils.isEmpty(orderVO.getDeliverTimes()) ? new ArrayList<>() : orderVO.getDeliverTimes());

        // Step 1-5 : 检查订单接口参数：优惠券列表
        for (OrderCouponVO coupon : orderVO.getCoupons()) {
            // 校验商家优惠券归属的会员
            if(coupon.getBelongType().equals(BelongTypeEnum.MERCHANT.getCode())) {
                if(NumberUtil.isNullOrNegativeZero(coupon.getVendorMemberId()) || NumberUtil.isNullOrNegativeZero(coupon.getVendorRoleId())) {
                    return Wrapper.fail(ResponseCode.ORDER_COUPON_VENDOR_ID_CAN_NOT_BE_NULL_OR_ZERO);
                }

                if(orderProducts.stream().noneMatch(p -> p.getVendorMemberId().equals(coupon.getVendorMemberId()) && p.getVendorRoleId().equals(coupon.getVendorRoleId()))) {
                    return Wrapper.fail(ResponseCode.ORDER_MERCHANT_COUPON_VENDOR_MUST_INCLUDE_IN_THE_PRODUCTS);
                }
            }

            //如果是商品优惠券，商品SkuId要大于0，且必须在商品列表中
            if (isProductCoupon(coupon.getBelongType(), coupon.getCouponType())) {
                if(NumberUtil.isNullOrNegativeZero(coupon.getSkuId())) {
                    return Wrapper.fail(ResponseCode.ORDER_COUPON_SKU_ID_SHOULD_GT_ZERO);
                }

                MobileOrderProductVO productVO = orderProducts.stream().filter(p -> p.getSkuId().equals(coupon.getSkuId())).findFirst().orElse(null);
                if(productVO == null) {
                    return Wrapper.fail(ResponseCode.ORDER_COUPON_SKU_ID_MUST_INCLUDE_IN_PRODUCTS);
                }

                //如果是0元抵扣券，购买商品的数量必须为1
                if((coupon.getBelongType().equals(BelongTypeEnum.PLATFORM.getCode()) && coupon.getCouponType().equals(PlatformCouponTypeEnum.ZERO_DISCOUNT.getCode())) || (coupon.getBelongType().equals(BelongTypeEnum.MERCHANT.getCode()) && coupon.getCouponType().equals(MerchantCouponTypeEnum.ZERO_DISCOUNT.getCode()))) {
                    if(productVO.getQuantity().compareTo(BigDecimal.ONE) != 0) {
                        return Wrapper.fail(ResponseCode.ORDER_ZERO_COUPON_SKU_QUANTITY_MUST_EQUAL_TO_ONE);
                    }
                }

                //优惠券不能用于赠品
                if(productVO.getPriceType().equals(PriceTypeEnum.Gift.getCode())) {
                    return Wrapper.fail(ResponseCode.ORDER_COUPON_CAN_NOT_USE_TO_GIFT_PRODUCT);
                }
            }
        }

        //Step 1-6: 最多只能使用一个平台优惠券
        if(orderVO.getCoupons().stream().filter(coupon -> coupon.getBelongType().equals(BelongTypeEnum.PLATFORM.getCode())).count() > 1) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_COUPON_CAN_NOT_EXCEED_ONE);
        }

        //****************************************************
        // Step 2: 从商品服务、会员服务查询商品详细信息，
        // 必须保证接口参数的商品与List<OrderProductDetailDTO>中的商品是一对一的关系（以SkuId判断）
        //****************************************************
        // Step 2-1: 在调用商品服务的接口中，校验下单接口传递的商品是否全包含在商品服务的查询结果中
        List<ProductSkuDTO> productStocks = orderProducts.stream().map(product -> new ProductSkuDTO(buyerMemberId, buyerRoleId, product.getVendorMemberId(), product.getVendorRoleId(), product.getSkuId(), product.getQuantity(), product.getPromotionType(), product.getGroupNo(), product.getParentSkuId())).collect(Collectors.toList());
        Wrapper<List<OrderProductDetailDTO>> productResult = productFeignService.findProductDetails(orderVO.getShopId(), buyerMemberId, buyerRoleId, buyerMemberLevelType, productStocks);
        if(productResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(productResult.getCode(), productResult.getMessage());
        }

        List<OrderProductDetailDTO> productDetails = productResult.getData();
        // Step 2-2: 校验是否有商品已经下架
        if(productDetails.stream().anyMatch(productDetail -> !productDetail.getPublished())) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_IS_OFF_LINE);
        }

        // Step 2-3: 重新构建商品单价
        for (OrderProductDetailDTO productDetail : productDetails) {
            Wrapper<BigDecimal> priceResult = findProductPrice(productDetail.getPriceMap(), productDetail.getQuantity());
            if(priceResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(priceResult.getCode(), priceResult.getMessage());
            }

            productDetail.setPrice(priceResult.getData());
        }

        // Step 2-3: 校验接口参数中所有商品的单价
        for (MobileOrderProductVO orderProduct : orderProducts) {
            OrderProductDetailDTO productDetail = productDetails.stream().filter(p -> p.getSkuId().equals(orderProduct.getSkuId())).findFirst().orElse(null);
            if(productDetail == null) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
            }

            if(orderProduct.getPrice().setScale(3, RoundingMode.HALF_UP).compareTo(productDetail.getPrice()) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_PRICE_IS_NOT_CORRECT);
            }
        }

        //****************************************************
        // Step 3: 从营销服务获得商品到手价、套餐、优惠活动等信息
        // 查询普通商品，套餐主商品，换购的商品、被换购的商品（查询普通商品、带营销活动的商品、套餐主商品、换购商品、被换购的商品，不查询套餐中的商品、赠品）
        //****************************************************
        Wrapper<List<PromotionProductDTO>> marketingResult = marketingFeignService.findOrderPromotions(orderVO.getShopId(), buyerMemberId, buyerRoleId, buyerMemberLevelType, productDetails);
        if(marketingResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(marketingResult.getCode(), marketingResult.getMessage());
        }
        
        List<PromotionProductDTO> promotionProducts = marketingResult.getData();

        //****************************************************
        // Step 4: 根据营销活动返回的结果，校验、修改
        //****************************************************
        for (MobileOrderProductVO orderProduct : orderProducts) {
            // 移除接口参数中与营销活动返回不匹配的营销活动
            List<PromotionDTO> promotions = promotionProducts.stream().filter(p -> p.getSkuId().equals(orderProduct.getSkuId())).flatMap(p -> p.getPromotions().stream()).collect(Collectors.toList());
            orderProduct.getPromotions().removeIf(promotion -> promotions.stream().noneMatch(r -> r.getPromotionId().equals(promotion.getPromotionId())));
        }

//        for (MobileOrderProductVO orderProduct : orderProducts) {
//            // 校验接口参数中商品关联的营销活动是否存在
//            if(!CollectionUtils.isEmpty(orderProduct.getPromotions())) {
//                List<PromotionDTO> promotions = promotionProducts.stream().filter(p -> p.getSkuId().equals(orderProduct.getSkuId())).flatMap(p -> p.getPromotions().stream()).collect(Collectors.toList());
//                if(orderProduct.getPromotions().stream().anyMatch(p -> promotions.stream().noneMatch(r -> r.getPromotionId().equals(p.getPromotionId())))) {
//                    return Wrapper.fail(ResponseCode.ORDER_PROMOTION_DOES_NOT_EXIST);
//                }
//            }
//        }

        // Step 4-1: 校验营销活动优惠金额
        BigDecimal promotionAmount = promotionProducts.stream().map(PromotionProductDTO::getPromotionAmount).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP);
        if(promotionAmount.setScale(2, RoundingMode.HALF_UP).compareTo(orderVO.getPromotionAmount().setScale(2, RoundingMode.HALF_UP)) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_PROMOTION_AMOUNT_MISMATCHED);
        }

        // Step 4-2: 套餐主商品、套餐中的商品、修改到手价
        List<OrderProductDetailDTO> primaryProducts = productDetails.stream().filter(product -> product.getPromotionType().equals(OrderPromotionTypeEnum.PRIMARY_OF_SET.getCode())).collect(Collectors.toList());
        for (OrderProductDetailDTO primaryProduct : primaryProducts) {
            PromotionProductDTO promotionProduct = promotionProducts.stream().filter(p -> p.getSkuId().equals(primaryProduct.getSkuId())).findFirst().orElse(null);
            if(promotionProduct == null || !promotionProduct.getPromotionType().equals(OrderPromotionTypeEnum.PRIMARY_OF_SET.getCode())) {
                return Wrapper.fail(ResponseCode.ORDER_PRIMARY_RODUCT_DOES_NOT_EXIST);
            }

            // 判断套餐中的商品是否都存在
            List<OrderProductDetailDTO> subProducts = productDetails.stream().filter(p -> promotionProduct.getSubProducts().stream().anyMatch(sub -> sub.getSkuId().equals(p.getSkuId()))).collect(Collectors.toList());
            if(CollectionUtils.isEmpty(subProducts) || subProducts.size() != promotionProduct.getSubProducts().size()) {
                return Wrapper.fail(ResponseCode.ORDER_SUB_PRODUCT_DOES_NOT_EXIST);
            }

            // 根据单价*数量，加权平均套餐到手价
            Map<Long, BigDecimal> baseMap = subProducts.stream().collect(Collectors.toMap(OrderProductDetailDTO::getSkuId, p -> p.getPrice().multiply(p.getQuantity()).setScale(3, RoundingMode.HALF_UP)));
            baseMap.put(primaryProduct.getSkuId(), primaryProduct.getPrice().multiply(primaryProduct.getQuantity()).setScale(3, RoundingMode.HALF_UP));

            Map<Long, BigDecimal> priceMap = weightedAmount(baseMap, promotionProduct.getRefPrice().multiply(promotionProduct.getQuantity()));

            // 重新设置套餐主商品、套餐商品的到手价
            subProducts.forEach(p -> p.setRefPrice(priceMap.getOrDefault(p.getSkuId(), BigDecimal.ZERO).divide(p.getQuantity(), 3, RoundingMode.HALF_UP)));
            primaryProduct.setRefPrice(priceMap.getOrDefault(primaryProduct.getSkuId(), BigDecimal.ZERO).divide(primaryProduct.getQuantity(), 3, RoundingMode.HALF_UP));
        }

        // Step 4-3: 除赠品、套餐主商品、套餐中商品外的其他商品，设置到手价
        List<OrderProductDetailDTO> otherProducts = productDetails.stream().filter(product -> !product.getPriceType().equals(PriceTypeEnum.Gift.getCode()) && !product.getPromotionType().equals(OrderPromotionTypeEnum.PRIMARY_OF_SET.getCode()) && !product.getPromotionType().equals(OrderPromotionTypeEnum.PART_OF_SET.getCode())).collect(Collectors.toList());
        for (OrderProductDetailDTO otherProduct : otherProducts) {
            PromotionProductDTO promotionProduct = promotionProducts.stream().filter(p -> p.getSkuId().equals(otherProduct.getSkuId())).findFirst().orElse(null);
            if(promotionProduct == null) {
                return Wrapper.fail(ResponseCode.ORDER_PROMOTION_PRODUCT_DOES_NOT_EXIST);
            }

            otherProduct.setRefPrice(promotionProduct.getRefPrice());
        }

        // Step 4-4: 判断赠品是否存在，设置到手价为0
        List<OrderProductDetailDTO> giftProducts = productDetails.stream().filter(product -> product.getPriceType().equals(PriceTypeEnum.Gift.getCode())).collect(Collectors.toList());
        for (OrderProductDetailDTO giftProduct : giftProducts) {
            if(promotionProducts.stream().flatMap(promotionProduct -> promotionProduct.getGifts().stream()).noneMatch(gift -> gift.getSkuId().equals(giftProduct.getSkuId()))) {
                return Wrapper.fail(ResponseCode.ORDER_GIFT_PRODUCT_DOES_NOT_EXIST);
            }

            giftProduct.setRefPrice(BigDecimal.ZERO);
        }

        //****************************************************
        // Step 5: 校验接口商品的到手价
        //****************************************************
        for (MobileOrderProductVO orderProduct : orderProducts) {
            OrderProductDetailDTO productDetail = productDetails.stream().filter(p -> p.getSkuId().equals(orderProduct.getSkuId())).findFirst().orElse(null);
            if(productDetail == null) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
            }

            //由于赠品、套餐主商品、套餐中的商品已经重新设置过到手价，这里不校验，并重新设置（在后续会有订单总金额的校验）
            if(productDetail.getPriceType().equals(PriceTypeEnum.Gift.getCode()) || productDetail.getPromotionType().equals(OrderPromotionTypeEnum.PRIMARY_OF_SET.getCode()) || productDetail.getPromotionType().equals(OrderPromotionTypeEnum.PART_OF_SET.getCode())) {
                //orderProduct.setRefPrice(productDetail.getRefPrice());
                continue;
            }

            if(orderProduct.getRefPrice().setScale(3, RoundingMode.HALF_UP).compareTo(productDetail.getRefPrice()) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_REF_PRICE_MISMATCHED, orderProduct.getName().concat(ResponseCode.ORDER_PRODUCT_REF_PRICE_MISMATCHED.getMessage()));
            }
        }

        //由于在计算优惠券的时候，会改变订单商品的到手价，所以这里先记录一下订单所有商品的金额，用于在后续校验订单实付金额
        BigDecimal productAmount = orderProducts.stream().map(p -> p.getRefPrice().multiply(p.getQuantity())).reduce(BigDecimal.ZERO, BigDecimal::add);

        //****************************************************
        //Step 6: 用所有营销活动的到手价，统计商品总额，查询优惠券
        //****************************************************
        BigDecimal promotionRefAmount = productDetails.stream().map(detail -> detail.getRefPrice().multiply(detail.getQuantity())).reduce(BigDecimal.ZERO, BigDecimal::add);
        Wrapper<List<OrderCouponDetailDTO>> couponResult = marketingFeignService.findOrderCoupons(orderVO.getShopId(), buyerMemberId, buyerRoleId, orderVO.getCoupons(), productDetails, promotionRefAmount);
        if(couponResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(couponResult.getCode(), couponResult.getMessage());
        }

        List<OrderCouponDetailDTO> couponDetails = couponResult.getData();
        //Step 6-1: 校验所有优惠券，根据优惠券重新调整商品到手价
        //定义一个Map，记录每个商品SkuId使用优惠券后减少的金额，返回用于在创建订单（拆单）时重新统计订单的优惠抵扣总额
        Map<Long, BigDecimal> couponMap = new HashMap<>();
        //再定义一个Map，记录每个商品SkuId使用“平台优惠券”后减少的金额，用于售后服务退款时返还平台优惠券
        Map<Long, BigDecimal> platformCouponMap = new HashMap<>();
        for (OrderCouponVO coupon : orderVO.getCoupons()) {
            OrderCouponDetailDTO couponDetail = couponDetails.stream().filter(c -> c.getCouponId().equals(coupon.getCouponId())).findFirst().orElse(null);
            if(couponDetail == null) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_DOES_NOT_EXIST);
            }

            // 校验适用商品的SkuId
            if(NumberUtil.notNullOrZero(coupon.getSkuId()) && !couponDetail.getSkuIds().contains(coupon.getSkuId())) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_SKU_ID_MISMATCHED);
            }

            // 校验卡券面额
            if(coupon.getAmount().setScale(3, RoundingMode.HALF_UP).compareTo(couponDetail.getAmount()) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_PRICE_MISMATCHED);
            }

            // 校验卡券归属和类型
            if(!coupon.getBelongType().equals(couponDetail.getBelongType()) || !coupon.getCouponType().equals(couponDetail.getCouponType())) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_TYPE_MISMATCHED);
            }

            // 校验卡券是否可用
            if(!couponDetail.getAvailable()) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_NOT_AVAILABLE);
            }

            // 校验卡券是否过期
            if(!(LocalDateTime.now().compareTo(couponDetail.getStartTime()) >= 0 && LocalDateTime.now().compareTo(couponDetail.getExpireTime()) <= 0)) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_EXPIRED);
            }

            //根据优惠券重新调整商品到手价（直接更新接口参数中的到手价）
            Map<Long, BigDecimal> couponAmountMap = modifyRefPrice(coupon, orderProducts);
            couponAmountMap.forEach((skuId, amount) -> couponMap.merge(skuId, amount, BigDecimal::add));
            //如果优惠券是“平台优惠券”，再单独记录使用“平台优惠券”的抵扣金额
            if(coupon.getBelongType().equals(BelongTypeEnum.PLATFORM.getCode())) {
                couponAmountMap.forEach((skuId, amount) -> platformCouponMap.merge(skuId, amount, BigDecimal::add));
            }
        }

        //校验计算后的优惠券减少金额
        BigDecimal couponAmount = couponMap.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        if(couponAmount.setScale(2, RoundingMode.HALF_UP).compareTo(orderVO.getCouponAmount().setScale(2, RoundingMode.HALF_UP)) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_COUPON_AMOUNT_MISMATCHED);
        }

        //****************************************************
        //Step 7: 校验运费
        //****************************************************
        //如果有满额包邮商品，则过滤满额包邮的商品，用于运费计算。默认为所有商品
        List<MobileOrderProductVO> freightProductList = orderProducts.stream().filter(p -> p.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode()) && p.getFreightType().equals(OrderFreightTypeEnum.BUYER.getCode())).collect(Collectors.toList());
        BigDecimal freightAmount = BigDecimal.ZERO;
        if (orderVO.getConsignee() != null) {
            List<MemberAndRoleIdDTO> memberList = freightProductList.stream().map(p -> {
                MemberAndRoleIdDTO member = new MemberAndRoleIdDTO();
                member.setMemberId(p.getVendorMemberId());
                member.setRoleId(p.getVendorRoleId());
                return member;
            }).collect(Collectors.toList());
            List<OrderFreeExpressConfigVO> freeExpressConfigList = orderParamConfigService.getOrderFreeExpressConfigList(memberList);

            Map<Long, BigDecimal> totalAmountMap = freightProductList.stream().collect(Collectors.toMap(MobileOrderProductVO::getVendorMemberId, p -> p.getRefPrice().multiply(p.getQuantity()), BigDecimal::add));

            freeExpressConfigList.forEach(configVO -> {
                BigDecimal totalAmount = totalAmountMap.getOrDefault(configVO.getMemberId(), BigDecimal.ZERO);
                if (totalAmount.compareTo(configVO.getOrderAmount()) >= 0) {
                    freightProductList.removeIf(p -> p.getVendorMemberId().equals(configVO.getMemberId()) && p.getVendorRoleId().equals(configVO.getRoleId()));
                }
            });

            Wrapper<BigDecimal> freightResult = logisticsFeignService.findOrderFreight(orderVO.getConsignee().getConsigneeId(), freightProductList.stream().map(p -> new LogisticsProductDetailBO(p.getLogisticsTemplateId(), p.getQuantity(), p.getWeight())).collect(Collectors.toList()));
            if (freightResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(freightResult.getCode(), freightResult.getMessage());
            }

            freightAmount = freightResult.getData().setScale(2, RoundingMode.HALF_UP);
        }

        if(orderVO.getFreight().setScale(2, RoundingMode.HALF_UP).compareTo(freightAmount) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_FREIGHT_AMOUNT_MISMATCHED);
        }

//        if(processPayment) {
//            BigDecimal totalAmount = (productAmount.add(freightAmount).subtract(couponAmount)).multiply(firstPayRate).setScale(2, RoundingMode.HALF_UP);
//            if(orderVO.getTotalAmount().setScale(2, RoundingMode.HALF_UP).compareTo(totalAmount) != 0) {
//                return Wrapper.fail(ResponseCode.ORDER_TOTAL_AMOUNT_MISMATCHED);
//            }
//        } else {
//            if(orderVO.getTotalAmount().compareTo(BigDecimal.ZERO) != 0) {
//                return Wrapper.fail(ResponseCode.ORDER_TOTAL_AMOUNT_MISMATCHED);
//            }
//        }

        //****************************************************
        //Step 8: 如果商品的配送方式为“自提”，从物流服务查询自提地址信息
        //****************************************************‘
        List<Long> addressIds = orderVO.getProducts().stream().filter(p -> p.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode())).map(MobileOrderProductVO::getAddressId).distinct().collect(Collectors.toList());
        Wrapper<List<ProductAddressDTO>> addressResult = logisticsFeignService.findProductAddresses(addressIds);
        if (addressResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(addressResult.getCode(), addressResult.getMessage());
        }
        //如果是自提，设置收货地址为自提地址用于待核销自提订单列表展示
        addressResult.getData().stream().findFirst().ifPresent(address -> {
            OrderConsigneeVO consignee = new OrderConsigneeVO();
            consignee.setConsigneeId(address.getAddressId());
            consignee.setConsignee(address.getReceiver());
            consignee.setProvinceCode(address.getProvinceCode());
            consignee.setCityCode(address.getCityCode());
            consignee.setDistrictCode(address.getDistrictCode());
            consignee.setStreetCode(StrUtil.isEmpty(address.getStreetCode()) ? "" : address.getStreetCode());
            consignee.setAddress(address.getAddress());
            consignee.setPhone(address.getPhone());
            consignee.setDefaultConsignee(false);
            orderVO.setConsignee(consignee);
        });

        orderVO.getProducts().forEach(product -> {
            if(product.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode())) {
                addressResult.getData().stream().filter(r -> r.getAddressId().equals(product.getAddressId())).findFirst().ifPresent(address -> {
                    product.setAddress(address.getAddress());
                    product.setReceiver(address.getReceiver());
                    product.setPhone(address.getPhone());
                });
            }
        });

        //****************************************************
        //Step 9: 计算积分抵扣
        //****************************************************
        //1. 根据供应商查询采购商抵扣金额
        //2. 抵扣金额根据供应商按比例再次降低商品到手价
        //3. 修改订单总金额字段
        List<OrderDeductionVO> deductions = orderVO.getDeductions();
        //计算积分抵扣总金额
        BigDecimal deductionAmount = BigDecimal.ZERO;
        Map<Long, BigDecimal> deductionMap = new HashMap<>();
        if (CollUtil.isNotEmpty(deductions)) {

            deductionAmount = orderVO.getDeductions().stream().map(OrderDeductionVO::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);

            for (OrderDeductionVO detailVO : deductions) {
                //根据单价*数量，计算平均到手价
                Map<Long, BigDecimal> weightedMap;
                if (MemberRelationTypeEnum.PLATFORM.getCode().equals(detailVO.getRelType())) {//平台积分
                    weightedMap = orderProducts.stream().collect(Collectors.toMap(MobileOrderProductVO::getSkuId, p -> p.getRefPrice().multiply(p.getQuantity())));
                } else {//店铺积分
                    weightedMap = orderProducts.stream().filter(p -> p.getVendorMemberId().equals(detailVO.getVendorMemberId())).collect(Collectors.toMap(MobileOrderProductVO::getSkuId, p -> p.getRefPrice().multiply(p.getQuantity())));
                }
                Map<Long, BigDecimal> deductionAmountMap = weightedAmount(weightedMap, detailVO.getAmount());
                deductionAmountMap.forEach((skuId, amount) -> deductionMap.merge(skuId, amount, BigDecimal::add));
                orderProducts.forEach(p -> {
                    BigDecimal refPrice = NumberUtil.max(p.getRefPrice().subtract(deductionAmountMap.getOrDefault(p.getSkuId(), BigDecimal.ZERO).divide(p.getQuantity(), 3, RoundingMode.HALF_UP)).setScale(3, RoundingMode.HALF_UP), BigDecimal.ZERO);
                    p.setRefPrice(refPrice);
                });
            }
        }

        //****************************************************
        //Step 10: 计算跨境电商进口商品税费
        //****************************************************
        //跨境商品，含税
        Map<Long, BigDecimal> taxesMap = productDetails.stream().filter(p -> p.getCrossBorder() != null && p.getCrossBorder() && p.getTax()).collect(Collectors.toMap(OrderProductDetailDTO::getSkuId, p -> p.getRefPrice().multiply(p.getTaxRate()).multiply(p.getQuantity()), BigDecimal::add));
        orderProducts.forEach(p -> {
            BigDecimal refPrice = NumberUtil.max(p.getRefPrice().add(taxesMap.getOrDefault(p.getSkuId(), BigDecimal.ZERO).divide(p.getQuantity(), 3, RoundingMode.HALF_UP)).setScale(3, RoundingMode.HALF_UP), BigDecimal.ZERO);
            p.setRefPrice(refPrice);
        });

        //校验订单实付金额（前端计算方式：实付金额 = (Σ到手价*数量 + 运费 - 优惠券金额 - 积分抵扣金额) * 第一次的支付比例）
        BigDecimal totalAmount;
        if(processPayment) {
            totalAmount = (productAmount.add(freightAmount).add(orderVO.getTaxes()).subtract(couponAmount).subtract(deductionAmount)).multiply(firstPayRate).setScale(2, RoundingMode.HALF_UP);
        } else {
            //如果不需要支付，实付金额 = (Σ到手价*数量 + 运费 - 优惠券金额 - 积分抵扣金额)
            totalAmount = (productAmount.add(freightAmount).add(orderVO.getTaxes()).subtract(couponAmount).subtract(deductionAmount)).setScale(2, RoundingMode.HALF_UP);
        }

        if(orderVO.getTotalAmount().setScale(2, RoundingMode.HALF_UP).compareTo(totalAmount) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_TOTAL_AMOUNT_MISMATCHED);
        }

        //赠送优惠券集合
        List<OrderGiveCouponDTO> orderGiveCouponDTOList = promotionProducts.stream().flatMap(p -> p.getGiveCouponDTOList().stream()).collect(Collectors.toList());

        // 结束返回
        return Wrapper.success(new BuyerOrderCheckBO(couponMap, platformCouponMap, deductionMap, taxesMap, freightProductList, orderGiveCouponDTOList));
    }

    /**
     * (商品、会员、物流、营销服务）查询商品详情、折扣、物流、促销活动等信息
     * @param buyerMemberId        采购会员Id
     * @param buyerRoleId          采购会员角色Id
     * @param buyerMemberLevelType 采购会员（当前登录用户）等级类型
     * @param orderVO              订单接口参数
     * @param vendorCount          供应商数量
     * @param processPayment       交易流程是否需要支付
     * @param firstPayRate         交易流程中第一批次中最小支付次数的支付比例
     * @return 校验、修改接口参数中的商品到手价格
     */
    @Override
    public Wrapper<BuyerOrderCheckBO> checkAgentPurchaseOrderProduct(Long buyerMemberId, Long buyerRoleId, Integer buyerMemberLevelType, AgentPurchaseOrderVO orderVO, int vendorCount, boolean processPayment, BigDecimal firstPayRate) {
        //****************************************************
        // Step 1： 接口参数、规则判断
        //****************************************************
        List<MobileOrderProductVO> orderProducts = orderVO.getProducts();
        // Step 1-1: 商品SkuId不能重复
        if (orderProducts.size() != orderProducts.stream().map(MobileOrderProductVO::getSkuId).distinct().count()) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_SKU_ID_DUPLICATED);
        }

        // Step 1-2 : 多供应商时，所有商品的运费方式必须为“无运费”或“卖家承担”
        if (vendorCount > 1 && orderProducts.stream().map(product -> NumberUtil.isNullOrNegative(product.getFreightType()) ? OrderFreightTypeEnum.VENDOR.getCode() : product.getFreightType()).anyMatch(freightType -> !freightType.equals(OrderFreightTypeEnum.VENDOR.getCode()))) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_FREIGHT_TYPE_MUST_BE_VENDOR);
        }

        // Step 1-3 : 到手价格：“普通商品”的到手价应该小于等于单价
        if (orderProducts.stream().filter(product -> NumberUtil.isNullOrZero(product.getPromotionType())).anyMatch(product -> product.getRefPrice().compareTo(product.getPrice()) > 0)) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_REF_PRICE_SHOULD_LTE_PRICE);
        }

        // Step 1-4 : 订单商品需要物流配送时，收货人信息不能为空
        if (orderProducts.stream().anyMatch(product -> product.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode())) && orderVO.getConsignee() == null) {
            return Wrapper.fail(ResponseCode.ORDER_CONSIGNEE_MUST_NOT_EMPTY);
        }

        // Step 1-4 : 检查订单接口参数：商品列表
        for (MobileOrderProductVO product : orderProducts) {
            //套餐主商品的套餐编号要大于0
            if (product.getPromotionType().equals(OrderPromotionTypeEnum.PRIMARY_OF_SET.getCode()) && NumberUtil.isNullOrNegativeZero(product.getGroupNo())) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_PRIMARY_OF_SET_GROUP_NO_SHOULD_GT_ZERO);
            }

            //如果是赠品，到手价要为0
            if (product.getPriceType().equals(PriceTypeEnum.Gift.getCode()) && product.getRefPrice().compareTo(BigDecimal.ZERO) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_GIFT_REF_PRICE_SHOULD_BE_ZERO);
            }

            //被换购商品的parentSkuId要大于0，并且存在于商品列表中
            if (product.getPromotionType().equals(OrderPromotionTypeEnum.EXCHANGED.getCode())) {
                if (NumberUtil.isNullOrNegativeZero(product.getParentSkuId())) {
                    return Wrapper.fail(ResponseCode.ORDER_EXCHANGED_PRODUCT_PARENT_SKU_ID_SHOULD_GT_ZERO);
                }

                if (orderVO.getProducts().stream().noneMatch(p -> p.getSkuId().equals(product.getParentSkuId()))) {
                    return Wrapper.fail(ResponseCode.ORDER_TO_EXCHANGED_PRODUCT_SKU_ID_SHOULD_INCLUDE_IN_PRODUCTS);
                }
            }

            //如果配送方式为“自提”，自提地址、联系人、电话不能为空
            if (product.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode()) && NumberUtil.isNullOrZero(product.getAddressId())) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_ADDRESS_ID_IS_MISSING);
            }

            //如果配送方式为“物流”，配送方式不能为空
            if (product.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode())) {
                if (NumberUtil.isNullOrZero(product.getFreightType())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_FREIGHT_TYPE_CAN_NOT_BE_NULL);
                }

                //如果运费类型为“买家承担”，物流模板Id、商品重量不能为空或0
                if (product.getFreightType().equals(OrderFreightTypeEnum.BUYER.getCode())) {
                    if (NumberUtil.isNullOrNegativeZero(product.getLogisticsTemplateId())) {
                        return Wrapper.fail(ResponseCode.ORDER_PRODUCT_LOGISTICS_TEMPLATE_ID_MUST_GREATER_THAN_ZERO);
                    }

                    if (NumberUtil.isNullOrNegativeZero(product.getWeight())) {
                        return Wrapper.fail(ResponseCode.ORDER_PRODUCT_WEIGHT_MUST_GREATER_THAN_ZERO);
                    }
                }
            }

            // 为方便后续校验，如果前端传Null值，将配送方式、自提地址Id，运费类型、营销活动列表设置为非Null值
            product.setDeliveryType(NumberUtil.isNullOrNegativeZero(product.getDeliveryType()) ? 0 : product.getDeliveryType());
            product.setAddressId(NumberUtil.isNullOrZero(product.getAddressId()) ? 0 : product.getAddressId());
            product.setFreightType(NumberUtil.isNullOrNegativeZero(product.getFreightType()) ? 0 : product.getFreightType());
            product.setPromotions(CollectionUtils.isEmpty(product.getPromotions()) ? new ArrayList<>() : product.getPromotions());
        }

        // 为方便后续校验，如果前端传Null值，将优惠券列表、积分抵扣列表、配送时间和备注设置成空列表
        orderVO.setCoupons(CollectionUtils.isEmpty(orderVO.getCoupons()) ? new ArrayList<>() : orderVO.getCoupons());
        orderVO.setDeductions(CollectionUtils.isEmpty(orderVO.getDeductions()) ? new ArrayList<>() : orderVO.getDeductions());
        orderVO.setDeliverTimes(CollectionUtils.isEmpty(orderVO.getDeliverTimes()) ? new ArrayList<>() : orderVO.getDeliverTimes());

        // Step 1-5 : 检查订单接口参数：优惠券列表
        for (OrderCouponVO coupon : orderVO.getCoupons()) {
            // 校验商家优惠券归属的会员
            if (coupon.getBelongType().equals(BelongTypeEnum.MERCHANT.getCode())) {
                if (NumberUtil.isNullOrNegativeZero(coupon.getVendorMemberId()) || NumberUtil.isNullOrNegativeZero(coupon.getVendorRoleId())) {
                    return Wrapper.fail(ResponseCode.ORDER_COUPON_VENDOR_ID_CAN_NOT_BE_NULL_OR_ZERO);
                }

                if (orderProducts.stream().noneMatch(p -> p.getVendorMemberId().equals(coupon.getVendorMemberId()) && p.getVendorRoleId().equals(coupon.getVendorRoleId()))) {
                    return Wrapper.fail(ResponseCode.ORDER_MERCHANT_COUPON_VENDOR_MUST_INCLUDE_IN_THE_PRODUCTS);
                }
            }

            //如果是商品优惠券，商品SkuId要大于0，且必须在商品列表中
            if (isProductCoupon(coupon.getBelongType(), coupon.getCouponType())) {
                if (NumberUtil.isNullOrNegativeZero(coupon.getSkuId())) {
                    return Wrapper.fail(ResponseCode.ORDER_COUPON_SKU_ID_SHOULD_GT_ZERO);
                }

                MobileOrderProductVO productVO = orderProducts.stream().filter(p -> p.getSkuId().equals(coupon.getSkuId())).findFirst().orElse(null);
                if (productVO == null) {
                    return Wrapper.fail(ResponseCode.ORDER_COUPON_SKU_ID_MUST_INCLUDE_IN_PRODUCTS);
                }

                //如果是0元抵扣券，购买商品的数量必须为1
                if ((coupon.getBelongType().equals(BelongTypeEnum.PLATFORM.getCode()) && coupon.getCouponType().equals(PlatformCouponTypeEnum.ZERO_DISCOUNT.getCode())) || (coupon.getBelongType().equals(BelongTypeEnum.MERCHANT.getCode()) && coupon.getCouponType().equals(MerchantCouponTypeEnum.ZERO_DISCOUNT.getCode()))) {
                    if (productVO.getQuantity().compareTo(BigDecimal.ONE) != 0) {
                        return Wrapper.fail(ResponseCode.ORDER_ZERO_COUPON_SKU_QUANTITY_MUST_EQUAL_TO_ONE);
                    }
                }

                //优惠券不能用于赠品
                if (productVO.getPriceType().equals(PriceTypeEnum.Gift.getCode())) {
                    return Wrapper.fail(ResponseCode.ORDER_COUPON_CAN_NOT_USE_TO_GIFT_PRODUCT);
                }
            }
        }

        //Step 1-6: 最多只能使用一个平台优惠券
        if (orderVO.getCoupons().stream().filter(coupon -> coupon.getBelongType().equals(BelongTypeEnum.PLATFORM.getCode())).count() > 1) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_COUPON_CAN_NOT_EXCEED_ONE);
        }

        //****************************************************
        // Step 2: 从商品服务、会员服务查询商品详细信息，
        // 必须保证接口参数的商品与List<OrderProductDetailDTO>中的商品是一对一的关系（以SkuId判断）
        //****************************************************
        // Step 2-1: 在调用商品服务的接口中，校验下单接口传递的商品是否全包含在商品服务的查询结果中
        List<ProductSkuDTO> productStocks = orderProducts.stream().map(product -> new ProductSkuDTO(buyerMemberId, buyerRoleId, product.getVendorMemberId(), product.getVendorRoleId(), product.getSkuId(), product.getQuantity(), product.getPromotionType(), product.getGroupNo(), product.getParentSkuId())).collect(Collectors.toList());
        Wrapper<List<OrderProductDetailDTO>> productResult = productFeignService.findProductDetails(orderVO.getShopId(), buyerMemberId, buyerRoleId, buyerMemberLevelType, productStocks);
        if (productResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(productResult.getCode(), productResult.getMessage());
        }

        List<OrderProductDetailDTO> productDetails = productResult.getData();
        // Step 2-2: 校验是否有商品已经下架
        if (productDetails.stream().anyMatch(productDetail -> !productDetail.getPublished())) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_IS_OFF_LINE);
        }

        // Step 2-3: 重新构建商品单价
        for (OrderProductDetailDTO productDetail : productDetails) {
            Wrapper<BigDecimal> priceResult = findProductPrice(productDetail.getPriceMap(), productDetail.getQuantity());
            if (priceResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(priceResult.getCode(), priceResult.getMessage());
            }

            productDetail.setPrice(priceResult.getData());
        }

        // Step 2-3: 校验接口参数中所有商品的单价
        for (MobileOrderProductVO orderProduct : orderProducts) {
            OrderProductDetailDTO productDetail = productDetails.stream().filter(p -> p.getSkuId().equals(orderProduct.getSkuId())).findFirst().orElse(null);
            if (productDetail == null) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
            }

            if (orderProduct.getPrice().setScale(3, RoundingMode.HALF_UP).compareTo(productDetail.getPrice()) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_PRICE_IS_NOT_CORRECT);
            }
        }

        //****************************************************
        // Step 3: 从营销服务获得商品到手价、套餐、优惠活动等信息
        // 查询普通商品，套餐主商品，换购的商品、被换购的商品（查询普通商品、带营销活动的商品、套餐主商品、换购商品、被换购的商品，不查询套餐中的商品、赠品）
        //****************************************************
        Wrapper<List<PromotionProductDTO>> marketingResult = marketingFeignService.findOrderPromotions(orderVO.getShopId(), buyerMemberId, buyerRoleId, buyerMemberLevelType, productDetails);
        if (marketingResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(marketingResult.getCode(), marketingResult.getMessage());
        }

        List<PromotionProductDTO> promotionProducts = marketingResult.getData();

        //****************************************************
        // Step 4: 根据营销活动返回的结果，校验、修改
        //****************************************************
        for (MobileOrderProductVO orderProduct : orderProducts) {
            // 移除接口参数中与营销活动返回不匹配的营销活动
            List<PromotionDTO> promotions = promotionProducts.stream().filter(p -> p.getSkuId().equals(orderProduct.getSkuId())).flatMap(p -> p.getPromotions().stream()).collect(Collectors.toList());
            orderProduct.getPromotions().removeIf(promotion -> promotions.stream().noneMatch(r -> r.getPromotionId().equals(promotion.getPromotionId())));
        }

//        for (MobileOrderProductVO orderProduct : orderProducts) {
//            // 校验接口参数中商品关联的营销活动是否存在
//            if(!CollectionUtils.isEmpty(orderProduct.getPromotions())) {
//                List<PromotionDTO> promotions = promotionProducts.stream().filter(p -> p.getSkuId().equals(orderProduct.getSkuId())).flatMap(p -> p.getPromotions().stream()).collect(Collectors.toList());
//                if(orderProduct.getPromotions().stream().anyMatch(p -> promotions.stream().noneMatch(r -> r.getPromotionId().equals(p.getPromotionId())))) {
//                    return Wrapper.fail(ResponseCode.ORDER_PROMOTION_DOES_NOT_EXIST);
//                }
//            }
//        }

        // Step 4-1: 校验营销活动优惠金额
        BigDecimal promotionAmount = promotionProducts.stream().map(PromotionProductDTO::getPromotionAmount).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP);
        if (promotionAmount.setScale(2, RoundingMode.HALF_UP).compareTo(orderVO.getPromotionAmount().setScale(2, RoundingMode.HALF_UP)) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_PROMOTION_AMOUNT_MISMATCHED);
        }

        // Step 4-2: 套餐主商品、套餐中的商品、修改到手价
        List<OrderProductDetailDTO> primaryProducts = productDetails.stream().filter(product -> product.getPromotionType().equals(OrderPromotionTypeEnum.PRIMARY_OF_SET.getCode())).collect(Collectors.toList());
        for (OrderProductDetailDTO primaryProduct : primaryProducts) {
            PromotionProductDTO promotionProduct = promotionProducts.stream().filter(p -> p.getSkuId().equals(primaryProduct.getSkuId())).findFirst().orElse(null);
            if (promotionProduct == null || !promotionProduct.getPromotionType().equals(OrderPromotionTypeEnum.PRIMARY_OF_SET.getCode())) {
                return Wrapper.fail(ResponseCode.ORDER_PRIMARY_RODUCT_DOES_NOT_EXIST);
            }

            // 判断套餐中的商品是否都存在
            List<OrderProductDetailDTO> subProducts = productDetails.stream().filter(p -> promotionProduct.getSubProducts().stream().anyMatch(sub -> sub.getSkuId().equals(p.getSkuId()))).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(subProducts) || subProducts.size() != promotionProduct.getSubProducts().size()) {
                return Wrapper.fail(ResponseCode.ORDER_SUB_PRODUCT_DOES_NOT_EXIST);
            }

            // 根据单价*数量，加权平均套餐到手价
            Map<Long, BigDecimal> baseMap = subProducts.stream().collect(Collectors.toMap(OrderProductDetailDTO::getSkuId, p -> p.getPrice().multiply(p.getQuantity()).setScale(3, RoundingMode.HALF_UP)));
            baseMap.put(primaryProduct.getSkuId(), primaryProduct.getPrice().multiply(primaryProduct.getQuantity()).setScale(3, RoundingMode.HALF_UP));

            Map<Long, BigDecimal> priceMap = weightedAmount(baseMap, promotionProduct.getRefPrice().multiply(promotionProduct.getQuantity()));

            // 重新设置套餐主商品、套餐商品的到手价
            subProducts.forEach(p -> p.setRefPrice(priceMap.getOrDefault(p.getSkuId(), BigDecimal.ZERO).divide(p.getQuantity(), 3, RoundingMode.HALF_UP)));
            primaryProduct.setRefPrice(priceMap.getOrDefault(primaryProduct.getSkuId(), BigDecimal.ZERO).divide(primaryProduct.getQuantity(), 3, RoundingMode.HALF_UP));
        }

        // Step 4-3: 除赠品、套餐主商品、套餐中商品外的其他商品，设置到手价
        List<OrderProductDetailDTO> otherProducts = productDetails.stream().filter(product -> !product.getPriceType().equals(PriceTypeEnum.Gift.getCode()) && !product.getPromotionType().equals(OrderPromotionTypeEnum.PRIMARY_OF_SET.getCode()) && !product.getPromotionType().equals(OrderPromotionTypeEnum.PART_OF_SET.getCode())).collect(Collectors.toList());
        for (OrderProductDetailDTO otherProduct : otherProducts) {
            PromotionProductDTO promotionProduct = promotionProducts.stream().filter(p -> p.getSkuId().equals(otherProduct.getSkuId())).findFirst().orElse(null);
            if (promotionProduct == null) {
                return Wrapper.fail(ResponseCode.ORDER_PROMOTION_PRODUCT_DOES_NOT_EXIST);
            }

            otherProduct.setRefPrice(promotionProduct.getRefPrice());
        }

        // Step 4-4: 判断赠品是否存在，设置到手价为0
        List<OrderProductDetailDTO> giftProducts = productDetails.stream().filter(product -> product.getPriceType().equals(PriceTypeEnum.Gift.getCode())).collect(Collectors.toList());
        for (OrderProductDetailDTO giftProduct : giftProducts) {
            if (promotionProducts.stream().flatMap(promotionProduct -> promotionProduct.getGifts().stream()).noneMatch(gift -> gift.getSkuId().equals(giftProduct.getSkuId()))) {
                return Wrapper.fail(ResponseCode.ORDER_GIFT_PRODUCT_DOES_NOT_EXIST);
            }

            giftProduct.setRefPrice(BigDecimal.ZERO);
        }

        //****************************************************
        // Step 5: 校验接口商品的到手价
        //****************************************************
        for (MobileOrderProductVO orderProduct : orderProducts) {
            OrderProductDetailDTO productDetail = productDetails.stream().filter(p -> p.getSkuId().equals(orderProduct.getSkuId())).findFirst().orElse(null);
            if (productDetail == null) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
            }

            //由于赠品、套餐主商品、套餐中的商品已经重新设置过到手价，这里不校验，并重新设置（在后续会有订单总金额的校验）
            if (productDetail.getPriceType().equals(PriceTypeEnum.Gift.getCode()) || productDetail.getPromotionType().equals(OrderPromotionTypeEnum.PRIMARY_OF_SET.getCode()) || productDetail.getPromotionType().equals(OrderPromotionTypeEnum.PART_OF_SET.getCode())) {
                //orderProduct.setRefPrice(productDetail.getRefPrice());
                continue;
            }

            if (orderProduct.getRefPrice().setScale(3, RoundingMode.HALF_UP).compareTo(productDetail.getRefPrice()) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_REF_PRICE_MISMATCHED, orderProduct.getName().concat(ResponseCode.ORDER_PRODUCT_REF_PRICE_MISMATCHED.getMessage()));
            }
        }

        //由于在计算优惠券的时候，会改变订单商品的到手价，所以这里先记录一下订单所有商品的金额，用于在后续校验订单实付金额
        BigDecimal productAmount = orderProducts.stream().map(p -> p.getRefPrice().multiply(p.getQuantity())).reduce(BigDecimal.ZERO, BigDecimal::add);

        //****************************************************
        //Step 6: 用所有营销活动的到手价，统计商品总额，查询优惠券
        //****************************************************
        BigDecimal promotionRefAmount = productDetails.stream().map(detail -> detail.getRefPrice().multiply(detail.getQuantity())).reduce(BigDecimal.ZERO, BigDecimal::add);
        Wrapper<List<OrderCouponDetailDTO>> couponResult = marketingFeignService.findOrderCoupons(orderVO.getShopId(), buyerMemberId, buyerRoleId, orderVO.getCoupons(), productDetails, promotionRefAmount);
        if (couponResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(couponResult.getCode(), couponResult.getMessage());
        }

        List<OrderCouponDetailDTO> couponDetails = couponResult.getData();
        //Step 6-1: 校验所有优惠券，根据优惠券重新调整商品到手价
        //定义一个Map，记录每个商品SkuId使用优惠券后减少的金额，返回用于在创建订单（拆单）时重新统计订单的优惠抵扣总额
        Map<Long, BigDecimal> couponMap = new HashMap<>();
        //再定义一个Map，记录每个商品SkuId使用“平台优惠券”后减少的金额，用于售后服务退款时返还平台优惠券
        Map<Long, BigDecimal> platformCouponMap = new HashMap<>();
        for (OrderCouponVO coupon : orderVO.getCoupons()) {
            OrderCouponDetailDTO couponDetail = couponDetails.stream().filter(c -> c.getCouponId().equals(coupon.getCouponId())).findFirst().orElse(null);
            if (couponDetail == null) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_DOES_NOT_EXIST);
            }

            // 校验适用商品的SkuId
            if (NumberUtil.notNullOrZero(coupon.getSkuId()) && !couponDetail.getSkuIds().contains(coupon.getSkuId())) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_SKU_ID_MISMATCHED);
            }

            // 校验卡券面额
            if (coupon.getAmount().setScale(3, RoundingMode.HALF_UP).compareTo(couponDetail.getAmount()) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_PRICE_MISMATCHED);
            }

            // 校验卡券归属和类型
            if (!coupon.getBelongType().equals(couponDetail.getBelongType()) || !coupon.getCouponType().equals(couponDetail.getCouponType())) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_TYPE_MISMATCHED);
            }

            // 校验卡券是否可用
            if (!couponDetail.getAvailable()) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_NOT_AVAILABLE);
            }

            // 校验卡券是否过期
            if (!(LocalDateTime.now().compareTo(couponDetail.getStartTime()) >= 0 && LocalDateTime.now().compareTo(couponDetail.getExpireTime()) <= 0)) {
                return Wrapper.fail(ResponseCode.ORDER_COUPON_EXPIRED);
            }

            //根据优惠券重新调整商品到手价（直接更新接口参数中的到手价）
            Map<Long, BigDecimal> couponAmountMap = modifyRefPrice(coupon, orderProducts);
            couponAmountMap.forEach((skuId, amount) -> couponMap.merge(skuId, amount, BigDecimal::add));
            //如果优惠券是“平台优惠券”，再单独记录使用“平台优惠券”的抵扣金额
            if (coupon.getBelongType().equals(BelongTypeEnum.PLATFORM.getCode())) {
                couponAmountMap.forEach((skuId, amount) -> platformCouponMap.merge(skuId, amount, BigDecimal::add));
            }
        }

        //校验计算后的优惠券减少金额
        BigDecimal couponAmount = couponMap.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        if (couponAmount.setScale(2, RoundingMode.HALF_UP).compareTo(orderVO.getCouponAmount().setScale(2, RoundingMode.HALF_UP)) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_COUPON_AMOUNT_MISMATCHED);
        }

        //****************************************************
        //Step 7: 校验运费
        //****************************************************
        //如果有满额包邮商品，则过滤满额包邮的商品，用于运费计算。默认为所有商品
        List<MobileOrderProductVO> freightProductList = orderProducts.stream().filter(p -> p.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode()) && p.getFreightType().equals(OrderFreightTypeEnum.BUYER.getCode())).collect(Collectors.toList());
        BigDecimal freightAmount = BigDecimal.ZERO;
        if (orderVO.getConsignee() != null) {
            List<MemberAndRoleIdDTO> memberList = freightProductList.stream().map(p -> {
                MemberAndRoleIdDTO member = new MemberAndRoleIdDTO();
                member.setMemberId(p.getVendorMemberId());
                member.setRoleId(p.getVendorRoleId());
                return member;
            }).collect(Collectors.toList());
            List<OrderFreeExpressConfigVO> freeExpressConfigList = orderParamConfigService.getOrderFreeExpressConfigList(memberList);

            Map<Long, BigDecimal> totalAmountMap = freightProductList.stream().collect(Collectors.toMap(MobileOrderProductVO::getVendorMemberId, p -> p.getRefPrice().multiply(p.getQuantity()), BigDecimal::add));

            freeExpressConfigList.forEach(configVO -> {
                BigDecimal totalAmount = totalAmountMap.getOrDefault(configVO.getMemberId(), BigDecimal.ZERO);
                if (totalAmount.compareTo(configVO.getOrderAmount()) >= 0) {
                    freightProductList.removeIf(p -> p.getVendorMemberId().equals(configVO.getMemberId()) && p.getVendorRoleId().equals(configVO.getRoleId()));
                }
            });

            Wrapper<BigDecimal> freightResult = logisticsFeignService.findOrderFreight(orderVO.getConsignee().getConsigneeId(), freightProductList.stream().map(p -> new LogisticsProductDetailBO(p.getLogisticsTemplateId(), p.getQuantity(), p.getWeight())).collect(Collectors.toList()));
            if (freightResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(freightResult.getCode(), freightResult.getMessage());
            }

            freightAmount = freightResult.getData().setScale(2, RoundingMode.HALF_UP);
        }

        if (orderVO.getFreight().setScale(2, RoundingMode.HALF_UP).compareTo(freightAmount) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_FREIGHT_AMOUNT_MISMATCHED);
        }

//        if(processPayment) {
//            BigDecimal totalAmount = (productAmount.add(freightAmount).subtract(couponAmount)).multiply(firstPayRate).setScale(2, RoundingMode.HALF_UP);
//            if(orderVO.getTotalAmount().setScale(2, RoundingMode.HALF_UP).compareTo(totalAmount) != 0) {
//                return Wrapper.fail(ResponseCode.ORDER_TOTAL_AMOUNT_MISMATCHED);
//            }
//        } else {
//            if(orderVO.getTotalAmount().compareTo(BigDecimal.ZERO) != 0) {
//                return Wrapper.fail(ResponseCode.ORDER_TOTAL_AMOUNT_MISMATCHED);
//            }
//        }

        //****************************************************
        //Step 8: 如果商品的配送方式为“自提”，从物流服务查询自提地址信息
        //****************************************************‘
        List<Long> addressIds = orderVO.getProducts().stream().filter(p -> p.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode())).map(MobileOrderProductVO::getAddressId).distinct().collect(Collectors.toList());
        Wrapper<List<ProductAddressDTO>> addressResult = logisticsFeignService.findProductAddresses(addressIds);
        if (addressResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(addressResult.getCode(), addressResult.getMessage());
        }
        //如果是自提，设置收货地址为自提地址用于待核销自提订单列表展示
        addressResult.getData().stream().findFirst().ifPresent(address -> {
            OrderConsigneeVO consignee = new OrderConsigneeVO();
            consignee.setConsigneeId(address.getAddressId());
            consignee.setConsignee(address.getReceiver());
            consignee.setProvinceCode(address.getProvinceCode());
            consignee.setCityCode(address.getCityCode());
            consignee.setDistrictCode(address.getDistrictCode());
            consignee.setStreetCode(StrUtil.isEmpty(address.getStreetCode()) ? "" : address.getStreetCode());
            consignee.setAddress(address.getAddress());
            consignee.setPhone(address.getPhone());
            consignee.setDefaultConsignee(false);
            orderVO.setConsignee(consignee);
        });

        orderVO.getProducts().forEach(product -> {
            if (product.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode())) {
                addressResult.getData().stream().filter(r -> r.getAddressId().equals(product.getAddressId())).findFirst().ifPresent(address -> {
                    product.setAddress(address.getAddress());
                    product.setReceiver(address.getReceiver());
                    product.setPhone(address.getPhone());
                });
            }
        });

        //****************************************************
        //Step 9: 计算积分抵扣
        //****************************************************
        //1. 根据供应商查询采购商抵扣金额
        //2. 抵扣金额根据供应商按比例再次降低商品到手价
        //3. 修改订单总金额字段
        List<OrderDeductionVO> deductions = orderVO.getDeductions();
        //计算积分抵扣总金额
        BigDecimal deductionAmount = BigDecimal.ZERO;
        Map<Long, BigDecimal> deductionMap = new HashMap<>();
        if (CollUtil.isNotEmpty(deductions)) {

            deductionAmount = orderVO.getDeductions().stream().map(OrderDeductionVO::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);

            for (OrderDeductionVO detailVO : deductions) {
                //根据单价*数量，计算平均到手价
                Map<Long, BigDecimal> weightedMap;
                if (MemberRelationTypeEnum.PLATFORM.getCode().equals(detailVO.getRelType())) {//平台积分
                    weightedMap = orderProducts.stream().collect(Collectors.toMap(MobileOrderProductVO::getSkuId, p -> p.getRefPrice().multiply(p.getQuantity())));
                } else {//店铺积分
                    weightedMap = orderProducts.stream().filter(p -> p.getVendorMemberId().equals(detailVO.getVendorMemberId())).collect(Collectors.toMap(MobileOrderProductVO::getSkuId, p -> p.getRefPrice().multiply(p.getQuantity())));
                }
                Map<Long, BigDecimal> deductionAmountMap = weightedAmount(weightedMap, detailVO.getAmount());
                deductionAmountMap.forEach((skuId, amount) -> deductionMap.merge(skuId, amount, BigDecimal::add));
                orderProducts.forEach(p -> {
                    BigDecimal refPrice = NumberUtil.max(p.getRefPrice().subtract(deductionAmountMap.getOrDefault(p.getSkuId(), BigDecimal.ZERO).divide(p.getQuantity(), 3, RoundingMode.HALF_UP)).setScale(3, RoundingMode.HALF_UP), BigDecimal.ZERO);
                    p.setRefPrice(refPrice);
                });
            }
        }

        //****************************************************
        //Step 10: 计算跨境电商进口商品税费
        //****************************************************
        //跨境商品，含税
        Map<Long, BigDecimal> taxesMap = productDetails.stream().filter(p -> p.getCrossBorder() != null && p.getCrossBorder() && p.getTax()).collect(Collectors.toMap(OrderProductDetailDTO::getSkuId, p -> p.getRefPrice().multiply(p.getTaxRate()).multiply(p.getQuantity()), BigDecimal::add));
        orderProducts.forEach(p -> {
            BigDecimal refPrice = NumberUtil.max(p.getRefPrice().add(taxesMap.getOrDefault(p.getSkuId(), BigDecimal.ZERO).divide(p.getQuantity(), 3, RoundingMode.HALF_UP)).setScale(3, RoundingMode.HALF_UP), BigDecimal.ZERO);
            p.setRefPrice(refPrice);
        });

        //校验订单实付金额（前端计算方式：实付金额 = (Σ到手价*数量 + 运费 - 优惠券金额 - 积分抵扣金额) * 第一次的支付比例）
        BigDecimal totalAmount;
        if (processPayment) {
            totalAmount = (productAmount.add(freightAmount).add(orderVO.getTaxes()).subtract(couponAmount).subtract(deductionAmount)).multiply(firstPayRate).setScale(2, RoundingMode.HALF_UP);
        } else {
            //如果不需要支付，实付金额 = (Σ到手价*数量 + 运费 - 优惠券金额 - 积分抵扣金额)
            totalAmount = (productAmount.add(freightAmount).add(orderVO.getTaxes()).subtract(couponAmount).subtract(deductionAmount)).setScale(2, RoundingMode.HALF_UP);
        }

        if (orderVO.getTotalAmount().setScale(2, RoundingMode.HALF_UP).compareTo(totalAmount) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_TOTAL_AMOUNT_MISMATCHED);
        }

        //赠送优惠券集合
        List<OrderGiveCouponDTO> orderGiveCouponDTOList = promotionProducts.stream().flatMap(p -> p.getGiveCouponDTOList().stream()).collect(Collectors.toList());

        // 结束返回
        return Wrapper.success(new BuyerOrderCheckBO(couponMap, platformCouponMap, deductionMap, taxesMap, freightProductList, orderGiveCouponDTOList));
    }


    /**
     * App - 拼团订单 - 查询商品详情、折扣、物流、促销活动等信息
     *
     * @param buyerMemberId        采购会员Id
     * @param buyerRoleId          采购会员角色Id
     * @param buyerMemberLevelType 采购会员（当前登录用户）等级类型
     * @param orderVO              订单接口参数
     * @param processPayment       交易流程是否需要支付
     * @param firstPayRate         交易流程中第一批次中最小支付次数的支付比例
     * @return 拼团Id
     */
    @Override
    public Wrapper<Long> checkMobileGroupOrderProductPrices(Long buyerMemberId, Long buyerRoleId, Integer buyerMemberLevelType, BuyerOrderVO orderVO, boolean processPayment, BigDecimal firstPayRate) {
        //****************************************************
        // Step 1： 接口参数、规则判断
        //****************************************************
        List<MobileOrderProductVO> orderProducts = orderVO.getProducts();

        // Step 1-1 : 订单商品需要物流配送时，收货人信息不能为空
        if(orderProducts.stream().anyMatch(product -> product.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode())) && orderVO.getConsignee() == null) {
            return Wrapper.fail(ResponseCode.ORDER_CONSIGNEE_MUST_NOT_EMPTY);
        }

        //Step 1-2 : 拼团订单的商品只有一个
        if(orderProducts.size() != 1) {
            return Wrapper.fail(ResponseCode.ORDER_GROUP_PRODUCT_MUST_BE_ONE);
        }

        // Step 1-2 : 检查订单接口参数：商品列表
        for (MobileOrderProductVO product : orderProducts) {
            //拼团商品不能为赠品
            if(product.getPriceType().equals(PriceTypeEnum.Gift.getCode())) {
                return Wrapper.fail(ResponseCode.ORDER_GROUP_PRODUCT_CAN_NOT_BE_GIFT);
            }

            //拼团商品的营销活动有且只有一个
            if(CollectionUtils.isEmpty(product.getPromotions()) || product.getPromotions().size() != 1) {
                return Wrapper.fail(ResponseCode.ORDER_GROUP_PROMOTION_NUMBER_MUST_EQ_ONE);
            }

            //检查所有营销活动类型
            if(product.getPromotions().stream().anyMatch(promotion -> !promotion.getPromotionType().equals(ActivityTypeEnum.GROUP_PURCHASE.getCode()))) {
                return Wrapper.fail(ResponseCode.ORDER_PROMOTION_TYPE_MISMATCHED);
            }

            //到手价格：应该小于等于单价
            if(product.getRefPrice().compareTo(product.getPrice()) > 0) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_REF_PRICE_SHOULD_LTE_PRICE);
            }

            //如果配送方式为“物流”，配送方式不能为空
            if(product.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode())) {
                if(NumberUtil.isNullOrZero(product.getFreightType())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_FREIGHT_TYPE_CAN_NOT_BE_NULL);
                }

                //如果运费类型为“买家承担”，物流模板Id、商品重量不能为空或0
                if(product.getFreightType().equals(OrderFreightTypeEnum.BUYER.getCode())) {
                    if(NumberUtil.isNullOrNegativeZero(product.getLogisticsTemplateId())) {
                        return Wrapper.fail(ResponseCode.ORDER_PRODUCT_LOGISTICS_TEMPLATE_ID_MUST_GREATER_THAN_ZERO);
                    }

                    if(NumberUtil.isNullOrNegativeZero(product.getWeight())) {
                        return Wrapper.fail(ResponseCode.ORDER_PRODUCT_WEIGHT_MUST_GREATER_THAN_ZERO);
                    }
                }
            }

            // 为方便后续校验，如果前端传Null值，将配送方式、运费类型、营销活动列表
            product.setFreightType(NumberUtil.isNullOrNegativeZero(product.getFreightType()) ? 0 : product.getFreightType());
        }

        // 为方便后续校验，如果前端传Null值，将配送时间和备注设置成空
        if(CollectionUtils.isEmpty(orderVO.getDeliverTimes())) {
            orderVO.setDeliverTimes(new ArrayList<>());
        }

        //拼团Id
        Long groupId = orderProducts.stream().flatMap(p -> p.getPromotions().stream()).map(p -> NumberUtil.isNullOrNegativeZero(p.getRecordId()) ? 0L : p.getRecordId()).findFirst().orElse(0L);
        //当前端传递拼团Id时，校验是否重复参与拼团
        if(NumberUtil.notNullAndPositive(groupId)) {
            Wrapper<Boolean> checkResult = marketingFeignService.checkGroupOrder(buyerMemberId, buyerRoleId, groupId);
            if (checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
            }

            if (checkResult.getData()) {
                return Wrapper.fail(ResponseCode.ORDER_BUYER_CAN_NOT_JOIN_ORDER_GROUP_REPEATED);
            }
        }

        //****************************************************
        // Step 2: 以商品关联的营销活动列表判断，
        //****************************************************
        //营销活动优惠金额
        BigDecimal promotionAmount = BigDecimal.ZERO;
        //商品价格
        BigDecimal productAmount = BigDecimal.ZERO;

        Wrapper<List<PromotionProductDTO>> marketingResult = marketingFeignService.findGroupOrderPromotions(orderVO.getShopId(), buyerMemberId, buyerRoleId, buyerMemberLevelType, orderVO.getProducts());
        if(marketingResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(marketingResult.getCode(), marketingResult.getMessage());
        }

        List<PromotionProductDTO> promotionProducts = marketingResult.getData();

        //Step 2-1: 根据营销活动返回的结果，校验接口商品的到手价
        for (MobileOrderProductVO orderProduct : orderProducts) {
            PromotionProductDTO promotionProduct = promotionProducts.stream().filter(p -> p.getSkuId().equals(orderProduct.getSkuId())).findFirst().orElse(null);
            if(promotionProduct == null) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
            }

            if(orderProduct.getRefPrice().setScale(3, RoundingMode.HALF_UP).compareTo(promotionProduct.getRefPrice()) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_REF_PRICE_MISMATCHED, orderProduct.getName().concat(ResponseCode.ORDER_PRODUCT_REF_PRICE_MISMATCHED.getMessage()));
            }

            //根据营销服务返回的营销活动列表，判断当前用户是否能购买拼团商品
            if(CollectionUtils.isEmpty(promotionProduct.getPromotions()) || promotionProduct.getPromotions().stream().noneMatch(promotion -> promotion.getPromotionId().equals(orderProduct.getPromotions().get(0).getPromotionId()))) {
                return Wrapper.fail(ResponseCode.ORDER_BUYER_CAN_NOT_CREATE_GROUP_ORDER);
            }

            //商品价格 = Σ(到手价 * 数量)
            productAmount = promotionAmount.add(orderProduct.getRefPrice().multiply(orderProduct.getQuantity()));
        }

        // 营销活动优惠金额
        promotionAmount = promotionProducts.stream().map(PromotionProductDTO::getPromotionAmount).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP);

        //****************************************************
        //Step 3: 校验营销活动优惠金额
        //****************************************************
        if(orderVO.getPromotionAmount().setScale(2, RoundingMode.HALF_UP).compareTo(promotionAmount.setScale(2, RoundingMode.HALF_UP)) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_PROMOTION_AMOUNT_MISMATCHED);
        }

        //****************************************************
        //Step 4: 校验运费
        //****************************************************
        BigDecimal freightAmount = BigDecimal.ZERO;
        if(orderVO.getConsignee() != null) {
            Wrapper<BigDecimal> freightResult = logisticsFeignService.findOrderFreight(orderVO.getConsignee().getConsigneeId(), orderProducts.stream().filter(p -> p.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode()) && p.getFreightType().equals(OrderFreightTypeEnum.BUYER.getCode())).map(p -> new LogisticsProductDetailBO(p.getLogisticsTemplateId(), p.getQuantity(), p.getWeight())).collect(Collectors.toList()));
            if(freightResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(freightResult.getCode(), freightResult.getMessage());
            }

            freightAmount = freightResult.getData().setScale(2, RoundingMode.HALF_UP);
        }

        if(orderVO.getFreight().setScale(2, RoundingMode.HALF_UP).compareTo(freightAmount) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_FREIGHT_AMOUNT_MISMATCHED);
        }

        //****************************************************
        //Step 5: 校验订单实付金额（前端计算方式：实付金额 = (Σ到手价*数量 + 运费) * 第一次的支付比例）
        //****************************************************
        if(processPayment) {
            BigDecimal totalAmount = (productAmount.add(freightAmount)).multiply(firstPayRate).setScale(2, RoundingMode.HALF_UP);
            if(orderVO.getTotalAmount().setScale(2, RoundingMode.HALF_UP).compareTo(totalAmount) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_TOTAL_AMOUNT_MISMATCHED);
            }
        } else {
            if(orderVO.getTotalAmount().compareTo(BigDecimal.ZERO) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_TOTAL_AMOUNT_MISMATCHED);
            }
        }

        //****************************************************
        //Step 6: 如果商品的配送方式为“自提”，从物流服务查询自提地址信息
        //****************************************************‘
        List<Long> addressIds = orderVO.getProducts().stream().filter(p -> p.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode())).map(MobileOrderProductVO::getAddressId).distinct().collect(Collectors.toList());
        Wrapper<List<ProductAddressDTO>> addressResult = logisticsFeignService.findProductAddresses(addressIds);
        if (addressResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(addressResult.getCode(), addressResult.getMessage());
        }
        //如果是自提，设置收货地址为自提地址用于待核销自提订单列表展示
        addressResult.getData().stream().findFirst().ifPresent(address -> {
            OrderConsigneeVO consignee = new OrderConsigneeVO();
            consignee.setConsigneeId(address.getAddressId());
            consignee.setConsignee(address.getReceiver());
            consignee.setProvinceCode(address.getProvinceCode());
            consignee.setCityCode(address.getCityCode());
            consignee.setDistrictCode(address.getDistrictCode());
            consignee.setStreetCode(StrUtil.isEmpty(address.getStreetCode()) ? "" : address.getStreetCode());
            consignee.setAddress(address.getAddress());
            consignee.setPhone(address.getPhone());
            consignee.setDefaultConsignee(false);
            orderVO.setConsignee(consignee);
        });

        orderVO.getProducts().forEach(product -> {
            if (product.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode())) {
                addressResult.getData().stream().filter(r -> r.getAddressId().equals(product.getAddressId())).findFirst().ifPresent(address -> {
                    product.setAddress(address.getAddress());
                    product.setReceiver(address.getReceiver());
                    product.setPhone(address.getPhone());
                });
            }
        });

        // 结束返回
        return Wrapper.success(groupId);
    }

    /**
     * 判断优惠券是否属于商品优惠券
     * @param belongType 优惠券归属类型
     * @param couponType 优惠券类型
     * @return 是-true，否-false
     */
    private Boolean isProductCoupon(Integer belongType, Integer couponType) {
        return (belongType.equals(BelongTypeEnum.PLATFORM.getCode()) && couponType.equals(PlatformCouponTypeEnum.ZERO_DISCOUNT.getCode())) || (belongType.equals(BelongTypeEnum.MERCHANT.getCode()) && (couponType.equals(MerchantCouponTypeEnum.ZERO_DISCOUNT.getCode()) || couponType.equals(MerchantCouponTypeEnum.COMMODITY.getCode())));
    }

    /**
     * 使用优惠券，重新计算商品到手价格
     * @param couponVO 接口参数
     * @param orderProducts 订单商品Dto列表
     * @return 优惠金额
     */
    private Map<Long, BigDecimal> modifyRefPrice(OrderCouponVO couponVO, List<MobileOrderProductVO> orderProducts) {
        BelongTypeEnum belongType = BelongTypeEnum.parse(couponVO.getBelongType());
        switch (belongType) {
            case PLATFORM:
                PlatformCouponTypeEnum platformCouponType = PlatformCouponTypeEnum.parse(couponVO.getCouponType());
                switch (platformCouponType) {
                    case ZERO_DISCOUNT:
                        // 0元抵扣优惠券只能用于一个商品，所以不需要判断数量
                        // 0元抵扣：到手价' = 0
                        // 优惠券减少金额 = 原到手价
                        Map<Long, BigDecimal> platformZeroCouponMap = new HashMap<>();
                        orderProducts.stream().filter(p -> p.getSkuId().equals(couponVO.getSkuId())).findFirst().ifPresent(p -> {
                            platformZeroCouponMap.putIfAbsent(p.getSkuId(), p.getRefPrice());
                            p.setRefPrice(BigDecimal.ZERO);
                        });
                        return platformZeroCouponMap;
                    case COMMON:
                        // 每个商品优惠券减少的金额 = （原到手价 * 优惠券面额）/Σ(原到手价 * 数量）
                        // 每个商品的 到手价' = Max[（原到手价 - 减少的金额 / 数量）, 0]
                        Map<Long, BigDecimal> weightedMap = orderProducts.stream().collect(Collectors.toMap(MobileOrderProductVO::getSkuId, p -> p.getRefPrice().multiply(p.getQuantity())));
                        Map<Long, BigDecimal> platformCommonCouponMap = weightedAmount(weightedMap, couponVO.getAmount());
                        orderProducts.forEach(p -> {
                            BigDecimal refPrice = NumberUtil.max(p.getRefPrice().subtract(platformCommonCouponMap.getOrDefault(p.getSkuId(), BigDecimal.ZERO).divide(p.getQuantity(), 3, RoundingMode.HALF_UP)).setScale(3, RoundingMode.HALF_UP), BigDecimal.ZERO);
                            p.setRefPrice(refPrice);
                        });
                        return platformCommonCouponMap;
                    default:
                        break;
                }
                break;
            case MERCHANT:
                MerchantCouponTypeEnum merchantCouponType = MerchantCouponTypeEnum.parse(couponVO.getCouponType());
                switch (merchantCouponType) {
                    case ZERO_DISCOUNT:
                        // 0元抵扣优惠券只能用于一个商品，所以不需要判断数量
                        //0元抵扣：到手价' = 0
                        //优惠券减少金额 = 原到手价
                        Map<Long, BigDecimal> zeroCouponMap = new HashMap<>();
                        orderProducts.stream().filter(p -> p.getVendorMemberId().equals(couponVO.getVendorMemberId()) && p.getVendorRoleId().equals(couponVO.getVendorRoleId()) && p.getSkuId().equals(couponVO.getSkuId())).findFirst().ifPresent(p -> {
                            zeroCouponMap.putIfAbsent(p.getSkuId(), p.getRefPrice());
                            p.setRefPrice(BigDecimal.ZERO);
                        });
                        return zeroCouponMap;
                    case COMMON:
                        // 每个商品优惠券减少的金额 = （原到手价 * 优惠券面额）/Σ(原到手价 * 数量）
                        // 每个商品的 到手价' = Max[（原到手价 - 减少的金额 / 数量）, 0]
                        Map<Long, BigDecimal> weightedMap = orderProducts.stream().filter(p -> p.getVendorMemberId().equals(couponVO.getVendorMemberId()) && p.getVendorRoleId().equals(couponVO.getVendorRoleId())).collect(Collectors.toMap(MobileOrderProductVO::getSkuId, p -> p.getRefPrice().multiply(p.getQuantity())));
                        Map<Long, BigDecimal> commonCouponMap = weightedAmount(weightedMap, couponVO.getAmount());
                        orderProducts.stream().filter(p -> p.getVendorMemberId().equals(couponVO.getVendorMemberId()) && p.getVendorRoleId().equals(couponVO.getVendorRoleId())).forEach(p -> {
                            BigDecimal refPrice = NumberUtil.max(p.getRefPrice().subtract(commonCouponMap.getOrDefault(p.getSkuId(), BigDecimal.ZERO).divide(p.getQuantity(), 3, RoundingMode.HALF_UP)).setScale(3, RoundingMode.HALF_UP), BigDecimal.ZERO);
                            p.setRefPrice(refPrice);
                        });
                        return commonCouponMap;
                    case CATEGORY:
                        break;
                    case BRAND:
                        break;
                    case COMMODITY:
                        //单个商品的优惠券，到手价' = Max[（原到手价 - 面额 / 数量）, 0]
                        //优惠券减少金额 = 面额
                        Map<Long, BigDecimal> productCouponMap = new HashMap<>();
                        orderProducts.stream().filter(p -> p.getVendorMemberId().equals(couponVO.getVendorMemberId()) && p.getVendorRoleId().equals(couponVO.getVendorRoleId()) && p.getSkuId().equals(couponVO.getSkuId())).findFirst().ifPresent(p -> {
                            BigDecimal refPrice = NumberUtil.max(BigDecimal.ZERO, p.getRefPrice().subtract(couponVO.getAmount().divide(p.getQuantity(), 3, RoundingMode.HALF_UP)).setScale(3, RoundingMode.HALF_UP));
                            productCouponMap.putIfAbsent(p.getSkuId(), couponVO.getAmount());
                            p.setRefPrice(refPrice);
                        });
                        return productCouponMap;
                }
                break;
            default:
                break;
        }

        return new HashMap<>();
    }

    /**
     * （拆单）加权平均拆单前订单的运费
     *
     * @param orderFreight 接口参数中的运费，即拆单前的订单运费
     * @param consigneeVO  接口参数中的收货人信息
     * @param vendorMap    拆单条件
     * @return 查询结果
     */
    @Override
    public Map<OrderSeparateDTO, BigDecimal> findSeparateOrderFreight(BigDecimal orderFreight, OrderConsigneeVO consigneeVO, Map<OrderSeparateDTO, BigDecimal> vendorMap) {
        //Step 1: 如果无收货人地址Id，运费即前端传递的运费
        //        如果只有一个供应商，且没有上游供应商，或同一个上游供应商，无需拆单，运费即为前端传递的运费
        if(NumberUtil.isNullOrZero(orderFreight) || consigneeVO == null || NumberUtil.isNullOrZero(consigneeVO.getConsigneeId()) || vendorMap.size() == 1) {
            return vendorMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, p -> orderFreight));
        }

        return findSeparateOrderFreight(orderFreight, vendorMap);
    }

    /**
     * （拆单）加权平均拆单前订单的运费
     *
     * @param orderFreight 接口参数中的运费，即拆单前的订单运费
     * @param vendorMap    拆单条件
     * @return 查询结果
     */
    @Override
    public Map<OrderSeparateDTO, BigDecimal> findSeparateOrderFreight(BigDecimal orderFreight, Map<OrderSeparateDTO, BigDecimal> vendorMap) {
        //如果运费为0，返回0
        if(orderFreight.compareTo(BigDecimal.ZERO) == 0) {
            return vendorMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, f -> BigDecimal.ZERO));
        }

        //Step 2: 计算总的重量*数量
        BigDecimal totalWeight = vendorMap.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);

        //Step 3: 如果所有拆单订单的 重量*数量为0（即没有商品有运费模板），返回 0
        if(totalWeight.compareTo(BigDecimal.ZERO) == 0) {
            return vendorMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, f -> BigDecimal.ZERO));
        }

        return vendorMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, f -> f.getValue().multiply(orderFreight).divide(totalWeight, 2, RoundingMode.HALF_UP)));
    }

    /**
     * （B2B订单）校验询价商品价格
     *
     * @param quoteNo  询价单号
     * @param products 订单商品列表
     * @return 校验结果
     */
    @Override
    public Wrapper<Void> checkBusinessOrderProductPrices(String quoteNo, List<BusinessOrderProductVO> products) {
        Wrapper<List<OrderQuotationDTO>> quoteResult = tradeFeignService.findInquiryOrderPrices(quoteNo);
        if(quoteResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(quoteResult.getCode(), quoteResult.getMessage());
        }

        if(CollectionUtils.isEmpty(quoteResult.getData()) || products.size() != quoteResult.getData().size()) {
            return Wrapper.fail(ResponseCode.ORDER_QUOTATION_DOES_NOT_EXIST);
        }

        if(quoteResult.getData().stream().anyMatch(quoteProduct -> products.stream().noneMatch(product -> product.getProductId().equals(quoteProduct.getProductId()) && product.getSkuId().equals(quoteProduct.getSkuId())))) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCTS_MISMATCH_QUOTATION_PRODUCTS);
        }

        for (BusinessOrderProductVO product : products) {
            OrderQuotationDTO quoteProduct = quoteResult.getData().stream().filter(p -> p.getProductId().equals(product.getProductId()) && p.getSkuId().equals(product.getSkuId())).findFirst().orElse(null);
            if(quoteProduct == null) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCTS_MISMATCH_QUOTATION_PRODUCTS);
            }

            if(product.getPrice().setScale(3, RoundingMode.HALF_UP).compareTo(quoteProduct.getPrice().setScale(3, RoundingMode.HALF_UP)) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_PRICE_IS_NOT_CORRECT);
            }

            if(product.getQuantity().setScale(3, RoundingMode.HALF_UP).compareTo(quoteProduct.getMinimumQuantity().setScale(3, RoundingMode.HALF_UP)) < 0) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_QUANTITY_LESS_THAN_QUOTATION);
            }

            if(product.getTaxRate().setScale(4, RoundingMode.HALF_UP).compareTo(quoteProduct.getTaxRate().setScale(4, RoundingMode.HALF_UP)) != 0) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_TAX_RATE_MISMATCH_QUOTATION);
            }

            //校验其他参数
            if(product.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode())) {
                if(!StringUtils.hasText(product.getReceiver())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_IS_MISSING);
                }

                if(!StringUtils.hasText(product.getPhone())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_PHONE_IS_MISSING);
                }

                if(!StringUtils.hasText(product.getAddress())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_ADDRESS_IS_MISSING);
                }
            }
        }

        return Wrapper.success();
    }

    /**
     * 校验现货采购订单商品价格
     *
     * @param buyerMemberId  采购会员Id
     * @param buyerRoleId    采购会员角色Id
     * @param memberType     登录用户的会员类型，以此判断采购商品是会员商品，还是渠道商品
     * @param shopId         前端商城Id
     * @param vendorMemberId 供应会员Id
     * @param vendorRoleId   供应会员角色Id
     * @param products       订单商品信息列表
     * @return 订单商品总价
     */
    @Override
    public Wrapper<BigDecimal> checkPurchaseOrderProductPrices(Long buyerMemberId, Long buyerRoleId, Integer memberType, Long shopId, Long vendorMemberId, Long vendorRoleId, List<PurchaseOrderProductVO> products) {
        //从商品服务获得商品阶梯价格
        Wrapper<Map<Long, Map<String, Double>>> priceResult = productFeignService.batchCheckProductPrice(vendorMemberId, vendorRoleId, shopId, memberType, products.stream().map(PurchaseOrderProductVO::getSkuId).collect(Collectors.toList()));
        if(priceResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(priceResult.getCode(), priceResult.getMessage());
        }

        // 校验商品价格
        for (PurchaseOrderProductVO product : products) {
            Map<String, Double> priceMap = priceResult.getData().get(product.getSkuId());
            if(priceMap == null) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
            }

            Wrapper<Void> priceCheckResult = checkProductPrice(priceMap, product.getQuantity(), product.getPrice());
            if(priceCheckResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(priceCheckResult.getCode(), priceCheckResult.getMessage());
            }

            //校验其他参数（需要判断运费模板Id）
            if(product.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode())) {
                if(!StringUtils.hasText(product.getReceiver())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_IS_MISSING);
                }

                if(!StringUtils.hasText(product.getPhone())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_PHONE_IS_MISSING);
                }

                if(!StringUtils.hasText(product.getAddress())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_ADDRESS_IS_MISSING);
                }
            }
        }

        //不计算折扣
        return Wrapper.success(products.stream().filter(product -> !product.getPriceType().equals(PriceTypeEnum.Gift.getCode())).map(product -> product.getPrice().multiply(product.getQuantity())).reduce(BigDecimal.ZERO, BigDecimal::add));
    }

    /**
     * （物流服务）查询现货采购订单运费
     *
     * @param consigneeVO 收货人信息
     * @param products    现货订单商品列表
     * @return 运费
     */
    @Override
    public Wrapper<BigDecimal> findPurchaseOrderFreight(BuyerOrderConsigneeVO consigneeVO, List<PurchaseOrderProductVO> products) {
        List<LogisticsProductDetailBO> logisticsProducts = products.stream().filter(product -> NumberUtil.notNullAndPositive(product.getLogisticsTemplateId()) && NumberUtil.notNullAndPositive(product.getWeight())).map(product ->{
            LogisticsProductDetailBO detailBO = new LogisticsProductDetailBO();
            detailBO.setTemplateId(product.getLogisticsTemplateId());
            detailBO.setQuantity(product.getQuantity());
            detailBO.setWeight(product.getWeight());
            return detailBO;
        }).collect(Collectors.toList());

        if(CollectionUtils.isEmpty(logisticsProducts)) {
            return Wrapper.success(BigDecimal.ZERO);
        }

        return logisticsFeignService.findOrderFreight(consigneeVO.getConsigneeId(), logisticsProducts);
    }

    /**
     * 校验采购订单商品接口参数
     *
     * @param order      订单
     * @param products   订单商品列表
     * @param isCreate   新增订单-true, 修改订单-false
     * @return 订单总金额，是否需要物流
     */
    @Override
    public Wrapper<OrderProductCheckBO> checkBuyerOrderProduct(OrderDO order, List<OrderProductVO> products, boolean isCreate) {
        //商品总金额
        BigDecimal productAmount = BigDecimal.ZERO;
        //是否包含“物流”配送方式
        boolean needLogistics = false;
        //购物车Id列表
        List<Long> cartIds = new ArrayList<>();

        List<OrderProductDO> productList = new ArrayList<>();
        for (OrderProductVO orderProductVO : products) {
            needLogistics = needLogistics || orderProductVO.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode());

            OrderProductDO product = new OrderProductDO();
            product.setOrder(order);
            product.setPriceType(orderProductVO.getPriceType());
            product.setProductId(orderProductVO.getProductId());
            product.setSkuId(orderProductVO.getSkuId());
            product.setStockId(NumberUtil.isNullOrZero(orderProductVO.getStockId()) ? 0L : orderProductVO.getStockId());
            product.setCartId(NumberUtil.isNullOrZero(orderProductVO.getCartId()) ? 0L : orderProductVO.getCartId());
            product.setProductNo("");
            product.setName(orderProductVO.getName());
            product.setCategory(orderProductVO.getCategory());
            product.setBrand(StringUtils.hasLength(orderProductVO.getBrand()) ? orderProductVO.getBrand() : "");
            product.setSpec(StringUtils.hasLength(orderProductVO.getSpec()) ? orderProductVO.getSpec() : "");
            product.setUnit(orderProductVO.getUnit());
            product.setLogo(orderProductVO.getLogo());
            product.setOriginalPrice(orderProductVO.getPrice());
            //商品单价 * 折扣 = 到手价
            product.setPrice(orderProductVO.getPrice());
            product.setDiscount(NumberUtil.notNullAndPositive(orderProductVO.getDiscount()) ? orderProductVO.getDiscount() : BigDecimal.ONE);
            product.setRefPrice(orderProductVO.getPriceType().equals(PriceTypeEnum.Gift.getCode()) ? BigDecimal.ZERO : product.getPrice().multiply(product.getDiscount()).setScale(3, RoundingMode.HALF_UP));
            product.setStock(NumberUtil.isNullOrNegative(orderProductVO.getStock()) ? BigDecimal.ZERO : orderProductVO.getStock());
            product.setQuantity(orderProductVO.getQuantity());
            product.setTax(orderProductVO.getTax() == null ? false : orderProductVO.getTax());
            product.setTaxRate(NumberUtil.notNullAndPositive(orderProductVO.getTaxRate()) ? orderProductVO.getTaxRate().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);
            product.setAmount(product.getRefPrice().multiply(orderProductVO.getQuantity()));
            //使用“平台优惠券”后的优惠抵扣金额
            product.setPlatformCouponAmount(BigDecimal.ZERO);
            product.setPaidAmount(BigDecimal.ZERO);
            product.setDeliverType(orderProductVO.getDeliveryType());
            product.setFreightType(NumberUtil.isNullOrNegative(orderProductVO.getFreightType()) ? OrderFreightTypeEnum.NONE.getCode() : orderProductVO.getFreightType());
            product.setWeight(NumberUtil.isNullOrNegativeZero(orderProductVO.getWeight()) ? BigDecimal.ZERO : orderProductVO.getWeight());
            product.setLogisticsTemplateId(NumberUtil.isNullOrNegativeZero(orderProductVO.getLogisticsTemplateId()) ? 0L : orderProductVO.getLogisticsTemplateId());
            product.setReceiver(StringUtils.hasLength(orderProductVO.getReceiver()) ? orderProductVO.getReceiver().trim() : "");
            product.setAddress(StringUtils.hasLength(orderProductVO.getAddress()) ? orderProductVO.getAddress().trim() : "");
            product.setPhone(StringUtils.hasLength(orderProductVO.getPhone()) ? orderProductVO.getPhone() : "");
            //转单商品标记为默认值
            product.setSeparateType(OrderSeparateTypeEnum.DEFAULT.getCode());
            product.setRelationId(0L);

            //关联报价单的商品
            product.setMaterial(null);
            //营销活动
            product.setPromotions(new HashSet<>());

            product.setDelivered(BigDecimal.ZERO);
            product.setReceived(BigDecimal.ZERO);
            product.setExchangeCount(BigDecimal.ZERO);
            product.setReturnCount(BigDecimal.ZERO);
            product.setMaintainCount(BigDecimal.ZERO);
            product.setReturnAmount(BigDecimal.ZERO);
            product.setEnhanceCount(BigDecimal.ZERO);
            product.setLeftCount(product.getQuantity());
            product.setDifferCount(BigDecimal.ZERO);

            productList.add(product);

            //不需要计算折扣（已经计算过了）
            productAmount = productAmount.add(product.getAmount());

            cartIds.add(product.getCartId());
        }

        if(!isCreate) {
            orderProductRepository.deleteByOrder(order);
        }

        orderProductRepository.saveAll(productList);
        order.setProducts(new HashSet<>(productList));
        return Wrapper.success(new OrderProductCheckBO(productAmount, needLogistics, cartIds));
    }

    /**
     * 校验积分兑换订单商品
     *
     * @param order          订单
     * @param orderProductVO 积分兑换商品
     * @return 订单总积分
     */
    @Override
    public Wrapper<OrderProductCheckBO> checkPointsOrderProduct(OrderDO order, PointsOrderProductVO orderProductVO) {
        OrderProductDO product = new OrderProductDO();
        product.setOrder(order);
        product.setPriceType(PriceTypeEnum.Score.getCode());
        product.setProductId(orderProductVO.getProductId());
        product.setSkuId(orderProductVO.getSkuId());
        product.setStockId(NumberUtil.isNullOrZero(orderProductVO.getStockId()) ? 0L : orderProductVO.getStockId());
        product.setCartId(0L);
        product.setProductNo("");
        product.setName(orderProductVO.getName());
        product.setCategory(orderProductVO.getCategory());
        product.setBrand(StringUtils.hasLength(orderProductVO.getBrand()) ? orderProductVO.getBrand() : "");
        product.setSpec(StringUtils.hasLength(orderProductVO.getSpec()) ? orderProductVO.getSpec() : "");
        product.setUnit(orderProductVO.getUnit());
        product.setLogo(orderProductVO.getLogo());
        product.setOriginalPrice(orderProductVO.getPrice());
        //积分订单：商品单价、到手价即兑换所需积分
        product.setPrice(orderProductVO.getPrice());
        product.setRefPrice(orderProductVO.getPrice());
        product.setStock(NumberUtil.isNullOrNegative(orderProductVO.getStock()) ? BigDecimal.ZERO : orderProductVO.getStock());
        product.setDiscount(BigDecimal.ONE);
        product.setQuantity(orderProductVO.getQuantity());
        product.setTax(orderProductVO.getTax() == null ? false : orderProductVO.getTax());
        product.setTaxRate(NumberUtil.notNullAndPositive(orderProductVO.getTaxRate()) ? orderProductVO.getTaxRate().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);
        product.setAmount(product.getRefPrice().multiply(orderProductVO.getQuantity()));
        //使用“平台优惠券”后的优惠抵扣金额
        product.setPlatformCouponAmount(BigDecimal.ZERO);
        product.setPaidAmount(BigDecimal.ZERO);
        product.setDeliverType(orderProductVO.getDeliveryType());
        //积分订单商品运费类型为“卖家承担”
        product.setFreightType(OrderFreightTypeEnum.VENDOR.getCode());
        product.setWeight(NumberUtil.isNullOrNegativeZero(orderProductVO.getWeight()) ? BigDecimal.ZERO : orderProductVO.getWeight());
        product.setLogisticsTemplateId(NumberUtil.isNullOrNegativeZero(orderProductVO.getLogisticsTemplateId()) ? 0L : orderProductVO.getLogisticsTemplateId());
        product.setReceiver(StringUtils.hasLength(orderProductVO.getReceiver()) ? orderProductVO.getReceiver().trim() : "");
        product.setAddress(StringUtils.hasLength(orderProductVO.getAddress()) ? orderProductVO.getAddress().trim() : "");
        product.setPhone(StringUtils.hasLength(orderProductVO.getPhone()) ? orderProductVO.getPhone() : "");
        //转单商品标记为默认值
        product.setSeparateType(OrderSeparateTypeEnum.DEFAULT.getCode());
        product.setRelationId(0L);

        //关联报价单的商品
        product.setMaterial(null);
        //营销活动
        product.setPromotions(new HashSet<>());

        product.setDelivered(BigDecimal.ZERO);
        product.setReceived(BigDecimal.ZERO);
        product.setExchangeCount(BigDecimal.ZERO);
        product.setReturnCount(BigDecimal.ZERO);
        product.setMaintainCount(BigDecimal.ZERO);
        product.setReturnAmount(BigDecimal.ZERO);
        product.setEnhanceCount(BigDecimal.ZERO);
        product.setLeftCount(product.getQuantity());
        product.setDifferCount(BigDecimal.ZERO);

        orderProductRepository.saveAndFlush(product);
        order.setProducts(Stream.of(product).collect(Collectors.toSet()));

        return Wrapper.success(new OrderProductCheckBO(product.getAmount(), product.getDeliverType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode()), new ArrayList<>()));
    }

    /**
     * 校验B2B订单商品
     *
     * @param order    订单
     * @param products 订单商品列表
     * @param isCreate 新增订单-true, 修改订单-false
     * @return 订单总金额，是否需要物流
     */
    @Override
    public Wrapper<OrderProductCheckBO> checkBusinessOrderProduct(OrderDO order, List<BusinessOrderProductVO> products, boolean isCreate) {
        //商品总金额
        BigDecimal productAmount = BigDecimal.ZERO;
        //是否包含“物流”配送方式
        boolean needLogistics = false;
        //购物车Id列表
        List<Long> cartIds = new ArrayList<>();

        List<OrderProductDO> productList = new ArrayList<>();
        for (BusinessOrderProductVO orderProductVO : products) {
            needLogistics = needLogistics || orderProductVO.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode());

            OrderProductDO product = new OrderProductDO();
            product.setOrder(order);
            product.setProductId(orderProductVO.getProductId());
            product.setSkuId(orderProductVO.getSkuId());
            product.setStockId(NumberUtil.isNullOrZero(orderProductVO.getStockId()) ? 0L : orderProductVO.getStockId());
            product.setCartId(NumberUtil.isNullOrZero(orderProductVO.getCartId()) ? 0L : orderProductVO.getCartId());
            product.setProductNo("");
            product.setName(orderProductVO.getName());
            product.setCategory(orderProductVO.getCategory());
            product.setBrand(StringUtils.hasLength(orderProductVO.getBrand()) ? orderProductVO.getBrand() : "");
            product.setSpec(StringUtils.hasLength(orderProductVO.getSpec()) ? orderProductVO.getSpec() : "");
            product.setUnit(orderProductVO.getUnit());
            product.setLogo(orderProductVO.getLogo());
            product.setOriginalPrice(orderProductVO.getPrice());
            //B2B订单：商品单价即到手价
            product.setPriceType(orderProductVO.getPriceType());
            product.setPrice(orderProductVO.getPrice());
            product.setDiscount(NumberUtil.isNullOrNegativeZero(orderProductVO.getDiscount()) ? BigDecimal.ONE : orderProductVO.getDiscount().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP));
            product.setRefPrice(orderProductVO.getPriceType().equals(PriceTypeEnum.Gift.getCode()) ? BigDecimal.ZERO : product.getPrice().multiply(product.getDiscount()));
            product.setStock(NumberUtil.isNullOrNegativeZero(orderProductVO.getStock()) ? BigDecimal.ZERO : orderProductVO.getStock());
            product.setQuantity(orderProductVO.getQuantity());
            product.setTax(orderProductVO.getTax() == null ? false : orderProductVO.getTax());
            product.setTaxRate(NumberUtil.notNullAndPositive(orderProductVO.getTaxRate()) ? orderProductVO.getTaxRate().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);
            product.setAmount(product.getRefPrice().multiply(orderProductVO.getQuantity()));
            //使用“平台优惠券”后的优惠抵扣金额
            product.setPlatformCouponAmount(BigDecimal.ZERO);
            product.setPaidAmount(BigDecimal.ZERO);
            product.setDeliverType(orderProductVO.getDeliveryType());
            product.setFreightType(OrderFreightTypeEnum.NONE.getCode());
            product.setWeight(NumberUtil.isNullOrNegativeZero(orderProductVO.getWeight()) ? BigDecimal.ZERO : orderProductVO.getWeight());
            product.setLogisticsTemplateId(NumberUtil.isNullOrNegativeZero(orderProductVO.getLogisticsTemplateId()) ? 0L : orderProductVO.getLogisticsTemplateId());
            product.setReceiver(StringUtils.hasLength(orderProductVO.getReceiver()) ? orderProductVO.getReceiver().trim() : "");
            product.setAddress(StringUtils.hasLength(orderProductVO.getAddress()) ? orderProductVO.getAddress().trim() : "");
            product.setPhone(StringUtils.hasLength(orderProductVO.getPhone()) ? orderProductVO.getPhone() : "");
            //转单商品标记为默认值
            product.setSeparateType(OrderSeparateTypeEnum.DEFAULT.getCode());
            product.setRelationId(0L);

            //关联报价单的商品
            product.setMaterial(null);
            //营销活动
            product.setPromotions(new HashSet<>());

            product.setDelivered(BigDecimal.ZERO);
            product.setReceived(BigDecimal.ZERO);
            product.setExchangeCount(BigDecimal.ZERO);
            product.setReturnCount(BigDecimal.ZERO);
            product.setMaintainCount(BigDecimal.ZERO);
            product.setReturnAmount(BigDecimal.ZERO);
            product.setEnhanceCount(BigDecimal.ZERO);
            product.setLeftCount(product.getQuantity());
            product.setDifferCount(BigDecimal.ZERO);

            productList.add(product);

            //不需要计算折扣（已经计算过了）
            productAmount = productAmount.add(product.getAmount());

            cartIds.add(product.getCartId());
        }

        if(!isCreate) {
            orderProductRepository.deleteByOrder(order);
        }

        orderProductRepository.saveAll(productList);
        order.setProducts(new HashSet<>(productList));
        return Wrapper.success(new OrderProductCheckBO(productAmount, needLogistics, cartIds));
    }

    /**
     * 校验B2B订单商品
     *
     * @param order    订单
     * @param products 订单商品列表
     * @param isCreate 新增订单-true, 修改订单-false
     * @return 订单总金额，是否需要物流
     */
    @Override
    public Wrapper<OrderProductCheckBO> checkPurchaseOrderProduct(OrderDO order, List<PurchaseOrderProductVO> products, boolean isCreate) {
        //商品总金额
        BigDecimal productAmount = BigDecimal.ZERO;
        //是否包含“物流”配送方式
        boolean needLogistics = false;

        List<OrderProductDO> productList = new ArrayList<>();
        for (PurchaseOrderProductVO orderProductVO : products) {
            needLogistics = needLogistics || orderProductVO.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode());
            OrderProductDO product = new OrderProductDO();
            product.setOrder(order);
            product.setProductId(orderProductVO.getProductId());
            product.setSkuId(orderProductVO.getSkuId());
            product.setStockId(NumberUtil.isNullOrZero(orderProductVO.getStockId()) ? 0L : orderProductVO.getStockId());
            product.setCartId(0L);
            product.setProductNo("");
            product.setName(orderProductVO.getName());
            product.setCategory(orderProductVO.getCategory());
            product.setBrand(StringUtils.hasLength(orderProductVO.getBrand()) ? orderProductVO.getBrand() : "");
            product.setSpec(StringUtils.hasLength(orderProductVO.getSpec()) ? orderProductVO.getSpec() : "");
            product.setUnit(orderProductVO.getUnit());
            product.setLogo(orderProductVO.getLogo());
            product.setOriginalPrice(orderProductVO.getPrice());
            //商品单价、到手价
            product.setPriceType(orderProductVO.getPriceType());
            product.setPrice(orderProductVO.getPrice());
            product.setDiscount(orderProductVO.getDiscount().setScale(4, RoundingMode.HALF_UP));
            product.setRefPrice(orderProductVO.getPriceType().equals(PriceTypeEnum.Gift.getCode()) ? BigDecimal.ZERO : product.getPrice().multiply(product.getDiscount()));
            product.setStock(NumberUtil.isNullOrNegativeZero(orderProductVO.getStock()) ? BigDecimal.ZERO : orderProductVO.getStock());
            product.setQuantity(orderProductVO.getQuantity());
            product.setTax(orderProductVO.getTax() == null ? false : orderProductVO.getTax());
            product.setTaxRate(NumberUtil.notNullAndPositive(orderProductVO.getTaxRate()) ? orderProductVO.getTaxRate().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);
            product.setAmount(product.getRefPrice().multiply(orderProductVO.getQuantity()));
            //使用“平台优惠券”后的优惠抵扣金额
            product.setPlatformCouponAmount(BigDecimal.ZERO);
            product.setPaidAmount(BigDecimal.ZERO);
            product.setDeliverType(orderProductVO.getDeliveryType());
            product.setFreightType(OrderFreightTypeEnum.NONE.getCode());
            product.setWeight(NumberUtil.isNullOrNegativeZero(orderProductVO.getWeight()) ? BigDecimal.ZERO : orderProductVO.getWeight());
            product.setLogisticsTemplateId(NumberUtil.isNullOrNegativeZero(orderProductVO.getLogisticsTemplateId()) ? 0L : orderProductVO.getLogisticsTemplateId());
            product.setReceiver(StringUtils.hasLength(orderProductVO.getReceiver()) ? orderProductVO.getReceiver().trim() : "");
            product.setAddress(StringUtils.hasLength(orderProductVO.getAddress()) ? orderProductVO.getAddress().trim() : "");
            product.setPhone(StringUtils.hasLength(orderProductVO.getPhone()) ? orderProductVO.getPhone() : "");
            //转单商品标记为默认值
            product.setSeparateType(OrderSeparateTypeEnum.DEFAULT.getCode());
            product.setRelationId(0L);

            //关联报价单的商品
            product.setMaterial(null);
            //营销活动
            product.setPromotions(new HashSet<>());

            product.setDelivered(BigDecimal.ZERO);
            product.setReceived(BigDecimal.ZERO);
            product.setExchangeCount(BigDecimal.ZERO);
            product.setReturnCount(BigDecimal.ZERO);
            product.setMaintainCount(BigDecimal.ZERO);
            product.setReturnAmount(BigDecimal.ZERO);
            product.setEnhanceCount(BigDecimal.ZERO);
            product.setLeftCount(product.getQuantity());
            product.setDifferCount(BigDecimal.ZERO);

            productList.add(product);

            //不需要计算折扣（已经计算过了）
            productAmount = productAmount.add(product.getAmount());
        }

        if(!isCreate) {
            orderProductRepository.deleteByOrder(order);
        }

        orderProductRepository.saveAll(productList);
        order.setProducts(new HashSet<>(productList));
        return Wrapper.success(new OrderProductCheckBO(productAmount, needLogistics, new ArrayList<>()));
    }

    /**
     * 校验App订单商品
     *
     * @param order    订单
     * @param products 订单商品列表
     * @param platformCouponMap platformCouponMap 商品SkuId使用“平台优惠券”的优惠金额
     * @return 订单总金额，是否需要物流
     */
    @Override
    public Wrapper<OrderProductCheckBO> checkMobileOrderProduct(OrderDO order, List<MobileOrderProductVO> products, Map<Long, BigDecimal> platformCouponMap) {
        //商品总金额
        BigDecimal productAmount = BigDecimal.ZERO;
        //是否包含“物流”配送方式
        boolean needLogistics = false;
        //购物车Id列表
        List<Long> cartIds = new ArrayList<>();

        List<OrderProductDO> productList = new ArrayList<>();
        for (MobileOrderProductVO orderProductVO : products) {
            needLogistics = needLogistics || orderProductVO.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode());

            OrderProductDO product = new OrderProductDO();
            product.setOrder(order);
            product.setProductId(orderProductVO.getProductId());
            product.setSkuId(orderProductVO.getSkuId());
            product.setStockId(NumberUtil.isNullOrZero(orderProductVO.getStockId()) ? 0L : orderProductVO.getStockId());
            product.setCartId(NumberUtil.isNullOrZero(orderProductVO.getCartId()) ? 0L : orderProductVO.getCartId());
            product.setProductNo("");
            product.setName(orderProductVO.getName());
            product.setCategory(orderProductVO.getCategory());
            product.setBrand(StringUtils.hasLength(orderProductVO.getBrand()) ? orderProductVO.getBrand() : "");
            product.setSpec(StringUtils.hasLength(orderProductVO.getSpec()) ? orderProductVO.getSpec() : "");
            product.setUnit(orderProductVO.getUnit());
            product.setLogo(orderProductVO.getLogo());
            product.setOriginalPrice(orderProductVO.getPrice());
            //App端由于有优惠券，所以要注意区分单价、到手价
            product.setPriceType(orderProductVO.getPriceType());
            product.setPrice(orderProductVO.getPrice());
            product.setDiscount(NumberUtil.isNullOrZero(orderProductVO.getDiscount()) ? BigDecimal.ONE : orderProductVO.getDiscount());
            //赠品的到手价为0，前端已经调用营销活动接口获得到手价，这里直接赋值
            product.setRefPrice(orderProductVO.getPriceType().equals(PriceTypeEnum.Gift.getCode()) ? BigDecimal.ZERO : orderProductVO.getRefPrice().setScale(3, RoundingMode.HALF_UP));
            product.setStock(NumberUtil.isNullOrNegative(orderProductVO.getStock()) ? BigDecimal.ZERO : orderProductVO.getStock());
            product.setQuantity(orderProductVO.getQuantity());
            product.setTax(orderProductVO.getTax() == null ? false : orderProductVO.getTax());
            product.setTaxRate(NumberUtil.notNullAndPositive(orderProductVO.getTaxRate()) ? orderProductVO.getTaxRate().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);
            product.setAmount(product.getRefPrice().multiply(orderProductVO.getQuantity()));
            //使用“平台优惠券”后的抵扣金额
            product.setPlatformCouponAmount(CollectionUtils.isEmpty(platformCouponMap) ? BigDecimal.ZERO : platformCouponMap.getOrDefault(orderProductVO.getSkuId(), BigDecimal.ZERO));
            product.setPaidAmount(BigDecimal.ZERO);
            product.setDeliverType(orderProductVO.getDeliveryType());
            product.setFreightType(NumberUtil.isNullOrNegative(orderProductVO.getFreightType()) ? OrderFreightTypeEnum.NONE.getCode() : orderProductVO.getFreightType());
            product.setWeight(NumberUtil.isNullOrNegativeZero(orderProductVO.getWeight()) ? BigDecimal.ZERO : orderProductVO.getWeight());
            product.setLogisticsTemplateId(NumberUtil.isNullOrNegativeZero(orderProductVO.getLogisticsTemplateId()) ? 0L : orderProductVO.getLogisticsTemplateId());
            product.setReceiver(StringUtils.hasLength(orderProductVO.getReceiver()) ? orderProductVO.getReceiver().trim() : "");
            product.setAddress(StringUtils.hasLength(orderProductVO.getAddress()) ? orderProductVO.getAddress().trim() : "");
            product.setPhone(StringUtils.hasLength(orderProductVO.getPhone()) ? orderProductVO.getPhone() : "");
            //转单商品标记为默认值
            product.setSeparateType(OrderSeparateTypeEnum.DEFAULT.getCode());
            product.setRelationId(0L);

            //关联报价单的商品
            product.setMaterial(null);

            product.setDelivered(BigDecimal.ZERO);
            product.setReceived(BigDecimal.ZERO);
            product.setExchangeCount(BigDecimal.ZERO);
            product.setReturnCount(BigDecimal.ZERO);
            product.setMaintainCount(BigDecimal.ZERO);
            product.setReturnAmount(BigDecimal.ZERO);
            product.setEnhanceCount(BigDecimal.ZERO);
            product.setLeftCount(product.getQuantity());
            product.setDifferCount(BigDecimal.ZERO);

            //保存营销活动
            Wrapper<Void> promotionResult = baseOrderPromotionService.checkProductPromotions(product, orderProductVO.getPromotions());
            if(promotionResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(promotionResult.getCode(), promotionResult.getMessage());
            }

            productList.add(product);

            productAmount = productAmount.add(product.getAmount());

            cartIds.add(product.getCartId());
        }

        orderProductRepository.saveAll(productList);
        order.setProducts(new HashSet<>(productList));
        return Wrapper.success(new OrderProductCheckBO(productAmount, needLogistics, cartIds));
    }

    /**
     * 校验、保存App 拼团订单商品
     *
     * @param order    订单
     * @param products 订单商品列表
     * @return 订单总金额，是否需要物流
     */
    @Override
    public Wrapper<OrderProductCheckBO> checkMobileGroupOrderProduct(OrderDO order, List<MobileOrderProductVO> products) {
        //商品总金额
        BigDecimal productAmount = BigDecimal.ZERO;
        //是否包含“物流”配送方式
        boolean needLogistics = false;

        List<OrderProductDO> productList = new ArrayList<>();
        for (MobileOrderProductVO orderProductVO : products) {
            needLogistics = needLogistics || orderProductVO.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode());

            OrderProductDO product = new OrderProductDO();
            product.setOrder(order);
            product.setProductId(orderProductVO.getProductId());
            product.setSkuId(orderProductVO.getSkuId());
            product.setStockId(NumberUtil.isNullOrZero(orderProductVO.getStockId()) ? 0L : orderProductVO.getStockId());
            product.setCartId(0L);
            product.setProductNo("");
            product.setName(orderProductVO.getName());
            product.setCategory(orderProductVO.getCategory());
            product.setBrand(StringUtils.hasLength(orderProductVO.getBrand()) ? orderProductVO.getBrand() : "");
            product.setSpec(StringUtils.hasLength(orderProductVO.getSpec()) ? orderProductVO.getSpec() : "");
            product.setUnit(orderProductVO.getUnit());
            product.setLogo(orderProductVO.getLogo());
            product.setOriginalPrice(orderProductVO.getPrice());
            //App端由于有优惠券，所以要注意区分单价、到手价
            product.setPriceType(orderProductVO.getPriceType());
            product.setPrice(orderProductVO.getPrice());
            //前端已经计算过会员折扣或拼团商品的到手价，这里直接赋值
            product.setDiscount(NumberUtil.isNullOrZero(orderProductVO.getDiscount()) ? BigDecimal.ONE : orderProductVO.getDiscount());
            product.setRefPrice(orderProductVO.getRefPrice().setScale(3, RoundingMode.HALF_UP));
            product.setStock(NumberUtil.isNullOrNegative(orderProductVO.getStock()) ? BigDecimal.ZERO : orderProductVO.getStock());
            product.setQuantity(orderProductVO.getQuantity());
            product.setTax(orderProductVO.getTax() == null ? false : orderProductVO.getTax());
            product.setTaxRate(NumberUtil.notNullAndPositive(orderProductVO.getTaxRate()) ? orderProductVO.getTaxRate().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);
            product.setAmount(product.getRefPrice().multiply(orderProductVO.getQuantity()));
            //使用“平台优惠券”后的优惠抵扣金额
            product.setPlatformCouponAmount(BigDecimal.ZERO);
            product.setPaidAmount(BigDecimal.ZERO);
            product.setDeliverType(orderProductVO.getDeliveryType());
            product.setFreightType(NumberUtil.isNullOrNegative(orderProductVO.getFreightType()) ? OrderFreightTypeEnum.NONE.getCode() : orderProductVO.getFreightType());
            product.setWeight(NumberUtil.isNullOrNegativeZero(orderProductVO.getWeight()) ? BigDecimal.ZERO : orderProductVO.getWeight());
            product.setLogisticsTemplateId(NumberUtil.isNullOrNegativeZero(orderProductVO.getLogisticsTemplateId()) ? 0L : orderProductVO.getLogisticsTemplateId());
            product.setReceiver(StringUtils.hasLength(orderProductVO.getReceiver()) ? orderProductVO.getReceiver().trim() : "");
            product.setAddress(StringUtils.hasLength(orderProductVO.getAddress()) ? orderProductVO.getAddress().trim() : "");
            product.setPhone(StringUtils.hasLength(orderProductVO.getPhone()) ? orderProductVO.getPhone() : "");
            //转单商品标记为默认值
            product.setSeparateType(OrderSeparateTypeEnum.DEFAULT.getCode());
            product.setRelationId(0L);

            //关联报价单的商品
            product.setMaterial(null);

            product.setDelivered(BigDecimal.ZERO);
            product.setReceived(BigDecimal.ZERO);
            product.setExchangeCount(BigDecimal.ZERO);
            product.setReturnCount(BigDecimal.ZERO);
            product.setMaintainCount(BigDecimal.ZERO);
            product.setReturnAmount(BigDecimal.ZERO);
            product.setEnhanceCount(BigDecimal.ZERO);
            product.setLeftCount(product.getQuantity());
            product.setDifferCount(BigDecimal.ZERO);

            //保存营销活动
            Wrapper<Void> promotionResult = baseOrderPromotionService.checkProductPromotions(product, orderProductVO.getPromotions());
            if(promotionResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(promotionResult.getCode(), promotionResult.getMessage());
            }

            productList.add(product);

            productAmount = productAmount.add(product.getAmount());
        }

        orderProductRepository.saveAll(productList);
        order.setProducts(new HashSet<>(productList));
        return Wrapper.success(new OrderProductCheckBO(productAmount, needLogistics, new ArrayList<>()));
    }

    /**
     * 校验Srm订单商品接口参数
     *
     * @param order    订单
     * @param products 订单物料列表
     * @param isCreate 是否新增，true表示新增， false表示修改
     * @return 订单总金融
     */
    @Override
    public Wrapper<OrderProductCheckBO> checkSrmOrderProduct(OrderDO order, List<SrmOrderProductVO> products, boolean isCreate) {
        //商品总金额
        BigDecimal productAmount = BigDecimal.ZERO;
        //是否包含“物流”配送方式
        boolean needLogistics = false;

        List<OrderProductDO> productList = new ArrayList<>();
        for (SrmOrderProductVO orderProductVO : products) {
            if(orderProductVO.getDeliveryType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode())) {
                if(!StringUtils.hasText(orderProductVO.getReceiver())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_IS_MISSING);
                }

                if(!StringUtils.hasText(orderProductVO.getPhone())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_PHONE_IS_MISSING);
                }

                if(!StringUtils.hasText(orderProductVO.getAddress())) {
                    return Wrapper.fail(ResponseCode.ORDER_PRODUCT_RECEIVER_ADDRESS_IS_MISSING);
                }
            }

            //以SkuId为判断条件，校验关联商品
            if(NumberUtil.notNullAndPositive(orderProductVO.getQuotedSkuId())) {
                if(!StringUtils.hasLength(orderProductVO.getQuotedName())) {
                    return Wrapper.fail(ResponseCode.ORDER_QUOTED_PRODUCT_NAME_CAN_NOT_BE_EMPTY);
                }
            }

            needLogistics = needLogistics || orderProductVO.getDeliveryType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode());

            OrderProductDO product = new OrderProductDO();
            product.setOrder(order);
            product.setProductId(orderProductVO.getProductId());
            product.setSkuId(0L);
            product.setStockId(0L);
            product.setCartId(0L);
            product.setProductNo(orderProductVO.getProductNo());
            product.setName(orderProductVO.getName());
            product.setCategory(orderProductVO.getCategory());
            product.setBrand(StringUtils.hasLength(orderProductVO.getBrand()) ? orderProductVO.getBrand() : "");
            product.setSpec(StringUtils.hasLength(orderProductVO.getSpec()) ? orderProductVO.getSpec() : "");
            product.setUnit(orderProductVO.getUnit());
            //物料没有Logo
            product.setLogo("");
            product.setOriginalPrice(orderProductVO.getPrice());
            //SRM订单：商品没有价格类型，商品单价即到手价
            product.setPriceType(0);
            product.setPrice(orderProductVO.getPrice());
            product.setRefPrice(orderProductVO.getPrice());
            product.setStock(NumberUtil.isNullOrNegative(orderProductVO.getStock()) ? BigDecimal.ZERO : orderProductVO.getStock());
            product.setDiscount(BigDecimal.ONE);
            product.setQuantity(orderProductVO.getQuantity());
            product.setTax(orderProductVO.getTax() == null ? false : orderProductVO.getTax());
            product.setTaxRate(NumberUtil.notNullAndPositive(orderProductVO.getTaxRate()) ? orderProductVO.getTaxRate().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);
            product.setAmount(product.getRefPrice().multiply(orderProductVO.getQuantity()));
            //使用“平台优惠券”后的优惠抵扣金额
            product.setPlatformCouponAmount(BigDecimal.ZERO);
            product.setPaidAmount(BigDecimal.ZERO);
            product.setDeliverType(orderProductVO.getDeliveryType());
            product.setFreightType(OrderFreightTypeEnum.NONE.getCode());
            product.setWeight(NumberUtil.isNullOrNegativeZero(orderProductVO.getWeight()) ? BigDecimal.ZERO : orderProductVO.getWeight());
            product.setLogisticsTemplateId(NumberUtil.isNullOrNegativeZero(orderProductVO.getLogisticsTemplateId()) ? 0L : orderProductVO.getLogisticsTemplateId());
            product.setReceiver(StringUtils.hasLength(orderProductVO.getReceiver()) ? orderProductVO.getReceiver().trim() : "");
            product.setAddress(StringUtils.hasLength(orderProductVO.getAddress()) ? orderProductVO.getAddress().trim() : "");
            product.setPhone(StringUtils.hasLength(orderProductVO.getPhone()) ? orderProductVO.getPhone() : "");
            //转单商品标记为默认值
            product.setSeparateType(OrderSeparateTypeEnum.DEFAULT.getCode());
            product.setRelationId(0L);

            //关联报价单的物料
            if(NumberUtil.isNullOrZero(orderProductVO.getQuotedSkuId())) {
                product.setMaterial(null);
            } else {
                OrderMaterialDO material = new OrderMaterialDO();
                material.setOrderProduct(product);
                material.setQuotedId(0L);
                material.setProductId(NumberUtil.isNullOrZero(orderProductVO.getQuotedProductId()) ? 0L : orderProductVO.getQuotedProductId());
                material.setProductNo("");
                material.setSkuId(orderProductVO.getQuotedSkuId());
                material.setName(orderProductVO.getQuotedName());
                material.setSpec(StringUtils.hasLength(orderProductVO.getQuotedSpec()) ? orderProductVO.getQuotedSpec() : "");
                material.setCategory(StringUtils.hasLength(orderProductVO.getQuotedCategory()) ? orderProductVO.getQuotedCategory() : "");
                material.setBrand(StringUtils.hasLength(orderProductVO.getQuotedBrand()) ? orderProductVO.getQuotedBrand() : "");
                material.setStock(BigDecimal.ZERO);
                //关联
                product.setMaterial(material);
            }

            //营销活动
            product.setPromotions(new HashSet<>());

            product.setDelivered(BigDecimal.ZERO);
            product.setReceived(BigDecimal.ZERO);
            product.setExchangeCount(BigDecimal.ZERO);
            product.setReturnCount(BigDecimal.ZERO);
            product.setMaintainCount(BigDecimal.ZERO);
            product.setReturnAmount(BigDecimal.ZERO);
            product.setEnhanceCount(BigDecimal.ZERO);
            product.setLeftCount(product.getQuantity());
            product.setDifferCount(BigDecimal.ZERO);

            productList.add(product);
            productAmount = productAmount.add(product.getAmount());
        }

        //如果是修改，删除原有数据
        if(!isCreate) {
            orderProductRepository.deleteByOrder(order);
        }

        orderProductRepository.saveAll(productList);

        order.setProducts(new HashSet<>(productList));
        return Wrapper.success(new OrderProductCheckBO(productAmount, needLogistics, new ArrayList<>()));
    }

    /**
     * （供应商）修改订单商品单价
     * @param order  订单
     * @param prices 接口参数
     * @return 修改结果
     */
    @Override
    public Wrapper<UpdateOrderProductPriceBO> vendorUpdateProductPrices(OrderDO order, List<VendorUpdateProductPriceVO> prices) {
        List<OrderProductDO> orderProducts = orderProductRepository.findByOrder(order);
        if (CollectionUtils.isEmpty(orderProducts) || prices.stream().anyMatch(price -> orderProducts.stream().noneMatch(orderProduct -> orderProduct.getId().equals(price.getOrderProductId())))) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
        }
        //商品修改信息用于记录在外部订单流转记录
        List<String> remarks = new ArrayList<>();

        List<OrderProductDO> updateProducts = orderProducts.stream().filter(orderProduct -> prices.stream().anyMatch(price -> price.getOrderProductId().equals(orderProduct.getId()))).peek(orderProduct -> prices.stream().filter(price -> price.getOrderProductId().equals(orderProduct.getId())).findFirst().ifPresent(price -> {
            //拼接商品名称+商品ID+修改前单价+修改后单价+修改原因
            String remark = orderProduct.getName() + "（商品ID：" + orderProduct.getProductId() + "）： 从￥" + NumberUtil.formatAmount(orderProduct.getRefPrice()) + "修改为￥" + NumberUtil.formatAmount(price.getPrice()) + "；原因为：" + price.getReason() + "；";
            remarks.add(remark);
            //修改到手价与商品总金额
            orderProduct.setRefPrice(price.getPrice());
            orderProduct.setAmount(orderProduct.getRefPrice().multiply(orderProduct.getQuantity()));
        })).collect(Collectors.toList());

        orderProductRepository.saveAll(updateProducts);

        return Wrapper.success(new UpdateOrderProductPriceBO(orderProducts.stream().map(OrderProductDO::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add), remarks));
    }

    /**
     * 转单 - 订单商品
     *
     * @param order                 转单后的订单
     * @param separateOrderProducts 原订单商品列表
     * @param supplyProducts        上游供应商商品列表
     * @return 订单总金额，是否需要物流
     */
    @Override
    public Wrapper<OrderProductCheckBO> transferOrderProduct(OrderDO order, List<OrderProductDO> separateOrderProducts, List<SupplyProductDTO> supplyProducts) {
        //商品总金额
        BigDecimal productAmount = BigDecimal.ZERO;
        //是否包含“物流”配送方式
        boolean needLogistics = false;

        List<OrderProductDO> productList = new ArrayList<>();
        for (OrderProductDO separateProduct : separateOrderProducts) {
            SupplyProductDTO supplyProduct = supplyProducts.stream().filter(product -> product.getVendorSkuId().equals(separateProduct.getSkuId())).findFirst().orElse(null);
            if(supplyProduct == null) {
                return Wrapper.fail(ResponseCode.ORDER_SUPPLY_PRODUCT_DOES_NOT_EXIST);
            }

            needLogistics = needLogistics || supplyProduct.getDeliverType().equals(OrderProductDeliverTypeEnum.LOGISTICS.getCode());

            OrderProductDO product = new OrderProductDO();
            product.setOrder(order);
            product.setProductId(supplyProduct.getProductId());
            product.setSkuId(supplyProduct.getSkuId());
            product.setStockId(0L);
            product.setCartId(0L);
            product.setProductNo(supplyProduct.getProductNo());
            product.setName(supplyProduct.getName());
            product.setCategory(supplyProduct.getCategory());
            product.setBrand(supplyProduct.getBrand());
            product.setSpec(supplyProduct.getSpec());
            product.setUnit(supplyProduct.getUnit());
            product.setLogo(supplyProduct.getLogo());
            product.setOriginalPrice(supplyProduct.getPrice());
            //转单后的订单：商品单价即到手价
            product.setPriceType(supplyProduct.getPriceType());
            product.setPrice(supplyProduct.getPrice());
            product.setDiscount(supplyProduct.getDiscount());
            product.setRefPrice(supplyProduct.getPriceType().equals(PriceTypeEnum.Gift.getCode()) ? BigDecimal.ZERO : product.getPrice().multiply(product.getDiscount()));
            product.setStock(supplyProduct.getStock());
            product.setQuantity(separateProduct.getQuantity());
            product.setTax(supplyProduct.getTax());
            product.setTaxRate(supplyProduct.getTaxRate());
            product.setAmount(product.getRefPrice().multiply(separateProduct.getQuantity()));
            //使用“平台优惠券”后的优惠抵扣金额
            product.setPlatformCouponAmount(BigDecimal.ZERO);
            product.setPaidAmount(BigDecimal.ZERO);
            product.setDeliverType(supplyProduct.getDeliverType());
            product.setFreightType(supplyProduct.getFreightType());
            product.setWeight(supplyProduct.getWeight());
            product.setLogisticsTemplateId(supplyProduct.getLogisticsTemplateId());
            product.setReceiver(supplyProduct.getReceiver());
            product.setAddress(supplyProduct.getAddress());
            product.setPhone(supplyProduct.getPhone());

            //转单商品标记
            product.setSeparateType(OrderSeparateTypeEnum.TRANSFERRED.getCode());
            product.setRelationId(separateProduct.getId());

            //转单商品没有关联报价单的物料
            product.setMaterial(null);
            //营销活动
            product.setPromotions(new HashSet<>());

            product.setDelivered(BigDecimal.ZERO);
            product.setReceived(BigDecimal.ZERO);
            product.setExchangeCount(BigDecimal.ZERO);
            product.setReturnCount(BigDecimal.ZERO);
            product.setMaintainCount(BigDecimal.ZERO);
            product.setReturnAmount(BigDecimal.ZERO);
            product.setEnhanceCount(BigDecimal.ZERO);
            product.setLeftCount(product.getQuantity());
            product.setDifferCount(BigDecimal.ZERO);

            productList.add(product);
            productAmount = productAmount.add(product.getAmount());
        }

        orderProductRepository.saveAll(productList);

        //设置转单前的订单的标记
        separateOrderProducts.forEach(separateProduct -> {
            separateProduct.setSeparateType(OrderSeparateTypeEnum.SEPARATED.getCode());
            productList.stream().filter(product -> product.getRelationId().equals(separateProduct.getId())).findFirst().ifPresent(product -> separateProduct.setRelationId(product.getId()));
        });

        orderProductRepository.saveAll(separateOrderProducts);

        order.setProducts(new HashSet<>(productList));
        return Wrapper.success(new OrderProductCheckBO(productAmount, needLogistics, new ArrayList<>()));
    }

    /**
     * 订单商品汇总信息
     *
     * @param order 订单
     * @return 订单商品汇总
     */
    @Override
    public OrderProductSummaryBO summaryOrderProducts(OrderDO order) {
        OrderProductSummaryBO summaryBO = new OrderProductSummaryBO();

        OrderProductSummaryVO summaryVO = new OrderProductSummaryVO();
        //商品总金额
        summaryVO.setProductAmount(NumberUtil.formatAmount(order.getProductAmount()));
        //运费
        summaryVO.setFreight(NumberUtil.formatAmount(order.getFreight()));
        //促销立减
        summaryVO.setPromotionAmount(NumberUtil.formatAmount(order.getPromotionAmount()));
        //优惠（券）立减
        summaryVO.setCouponAmount(NumberUtil.formatAmount(order.getCouponAmount()));
        //积分抵扣总金额
        summaryVO.setDeductionAmount(NumberUtil.formatAmount(order.getDeductionAmount()));
        //税费
        summaryVO.setTaxes(NumberUtil.formatAmount(order.getTaxes()));
        //订单总金额
        summaryVO.setTotalAmount(NumberUtil.formatAmount(order.getTotalAmount()));

        //是否全部发货完毕
        AtomicBoolean deliveryDone = new AtomicBoolean(true);
        //是否全部收货完毕
        AtomicBoolean receiveDone = new AtomicBoolean(true);

        List<OrderProductDO> orderProducts = orderProductRepository.findByOrder(order, Sort.by("id").ascending());
        summaryVO.setProducts(orderProducts.stream().map(product -> {
            OrderProductDetailVO detailVO = new OrderProductDetailVO();
            detailVO.setOrderProductId(product.getId());
            detailVO.setProductId(product.getProductId());
            detailVO.setSkuId(product.getSkuId());
            detailVO.setStockId(product.getStockId());
            detailVO.setPriceType(product.getPriceType());
            detailVO.setProductNo(StringUtils.hasLength(product.getProductNo()) ? product.getProductNo() : "");
            detailVO.setName(product.getName());
            detailVO.setLogo(product.getLogo());
            detailVO.setCategory(product.getCategory());
            detailVO.setBrand(product.getBrand());
            detailVO.setUnit(product.getUnit());
            detailVO.setSpec(StringUtils.hasLength(product.getSpec()) ? product.getSpec() : "");
            detailVO.setPrice(NumberUtil.formatAmount(product.getRefPrice()));
            detailVO.setDiscount(NumberUtil.formatRoundHalfUp(product.getDiscount()));
            detailVO.setQuantity(NumberUtil.formatToInteger(product.getQuantity()));
            detailVO.setTax(product.getTax());
            detailVO.setTaxRate(NumberUtil.formatRoundHalfUp(product.getTaxRate()));
            detailVO.setAmount(NumberUtil.formatAmount(product.getAmount()));
            detailVO.setStock(NumberUtil.formatToInteger(product.getStock()));
            detailVO.setDeliverType(product.getDeliverType());
            detailVO.setDeliverTypeName(OrderProductDeliverTypeEnum.getNameByCode(product.getDeliverType()));
            detailVO.setWeight(product.getWeight());
            detailVO.setLogisticsTemplateId(product.getLogisticsTemplateId());
            detailVO.setReceiver(product.getReceiver());
            detailVO.setAddress(product.getAddress());
            detailVO.setPhone(product.getPhone());
            //以收货、发货数量大于等于采购数量为条件，判断是否收货完毕、发货完毕
            deliveryDone.set(deliveryDone.get() && (product.getDelivered().compareTo(product.getQuantity()) >= 0));
            receiveDone.set(receiveDone.get() && (product.getReceived().compareTo(product.getQuantity()) >= 0));
            if(product.getMaterial() != null) {
                detailVO.setQuotedId(product.getMaterial().getQuotedId());
                detailVO.setQuotedProductId(product.getMaterial().getProductId());
                detailVO.setQuotedSkuId(product.getMaterial().getSkuId());
                detailVO.setQuotedProductNo(product.getMaterial().getProductNo());
                detailVO.setQuotedName(product.getMaterial().getName());
                detailVO.setQuotedSpec(product.getMaterial().getSpec());
                detailVO.setQuotedCategory(product.getMaterial().getCategory());
                detailVO.setQuotedBrand(product.getMaterial().getBrand());
                detailVO.setQuotedStock(NumberUtil.formatToInteger(product.getMaterial().getStock()));
            }
            return detailVO;
        }).collect(Collectors.toList()));

        summaryBO.setDeliveryDone(deliveryDone.get());
        summaryBO.setReceiveDone(receiveDone.get());
        summaryBO.setProductSummary(summaryVO);

        summaryBO.setDeliverySummaries(orderProducts.stream().map(product -> {
            OrderDeliverySummaryVO detailVO = new OrderDeliverySummaryVO();
            detailVO.setProductId(product.getProductId());
            detailVO.setSkuId(product.getSkuId());
            detailVO.setProductNo(product.getProductNo());
            detailVO.setName(product.getName());
            detailVO.setCategory(product.getCategory());
            detailVO.setBrand(product.getBrand());
            detailVO.setUnit(product.getUnit());
            detailVO.setSpec(product.getSpec());
            detailVO.setPrice(NumberUtil.formatAmount(product.getRefPrice()));
            detailVO.setDiscount(NumberUtil.formatRoundHalfUp(product.getDiscount()));
            detailVO.setQuantity(NumberUtil.formatToInteger(product.getQuantity()));
            detailVO.setTax(product.getTax());
            detailVO.setTaxRate(NumberUtil.formatRoundHalfUp(product.getTaxRate()));
            detailVO.setQuotedId(product.getMaterial() == null ? 0L : product.getMaterial().getQuotedId());
            detailVO.setQuotedProductId(product.getMaterial() == null ? 0L : product.getMaterial().getProductId());
            detailVO.setQuotedSkuId(product.getMaterial() == null ? 0L : product.getMaterial().getSkuId());
            detailVO.setQuotedProductNo(product.getMaterial() == null ? "" : product.getMaterial().getProductNo());
            detailVO.setQuotedName(product.getMaterial() == null ? "" : (StringUtils.hasLength(product.getMaterial().getSpec()) ? product.getMaterial().getName().concat("/").concat(product.getMaterial().getSpec()) : product.getMaterial().getName()));
            detailVO.setQuotedCategory(product.getMaterial() == null ? "" : product.getMaterial().getCategory());
            detailVO.setQuotedBrand(product.getMaterial() == null ? "" : product.getMaterial().getBrand());
            detailVO.setQuotedSpec(product.getMaterial() == null ? "" : product.getMaterial().getSpec());
            detailVO.setAmount(NumberUtil.formatAmount(product.getAmount()));
            detailVO.setDelivered(NumberUtil.formatToInteger(product.getDelivered()));
            detailVO.setReceived(NumberUtil.formatToInteger(product.getReceived()));
            detailVO.setLeftCount(NumberUtil.formatToInteger(product.getLeftCount()));
            detailVO.setDifferCount(NumberUtil.formatToInteger(product.getDifferCount()));
            return detailVO;
        }).collect(Collectors.toList()));

        return summaryBO;
    }

    /**
     * 查询供应订单待发货商品信息
     *
     * @param order 订单
     * @return 订单商品
     */
    @Override
    public List<VendorDeliveryProductVO> listVendorDeliveryProducts(OrderDO order) {
        return orderProductRepository.findByOrder(order).stream().map(product -> {
            VendorDeliveryProductVO productVO = new VendorDeliveryProductVO();
            productVO.setOrderProductId(product.getId());
            productVO.setRelationId(product.getRelationId());
            productVO.setProductId(product.getProductId());
            productVO.setSkuId(product.getSkuId());
            productVO.setProductNo(product.getProductNo());
            productVO.setName(product.getName());
            productVO.setCategory(product.getCategory());
            productVO.setSpec(product.getSpec());
            productVO.setBrand(product.getBrand());
            productVO.setUnit(product.getUnit());
            if(product.getMaterial() != null) {
                productVO.setQuotedProductId(product.getMaterial().getProductId());
                productVO.setQuotedSkuId(product.getMaterial().getSkuId());
                productVO.setQuotedProductNo(product.getMaterial().getProductNo());
                productVO.setQuotedName(StringUtils.hasLength(product.getMaterial().getSpec()) ? product.getMaterial().getName().concat("/").concat(product.getMaterial().getSpec()) : product.getMaterial().getName());
                productVO.setQuotedSpec(product.getMaterial().getSpec());
                productVO.setQuotedCategory(product.getMaterial().getCategory());
                productVO.setQuotedBrand(product.getMaterial().getBrand());
            }
            productVO.setQuantity(NumberUtil.formatToInteger(product.getQuantity()));
            productVO.setDelivered(NumberUtil.formatToInteger(product.getDelivered()));
            productVO.setReceived(NumberUtil.formatToInteger(product.getReceived()));
            productVO.setLeftCount(NumberUtil.formatToInteger(product.getLeftCount()));
            productVO.setDifferCount(NumberUtil.formatToInteger(product.getDifferCount()));
            return productVO;
        }).collect(Collectors.toList());
    }

    /**
     * 修改订单商品的已支付金额
     *
     * @param order     订单
     * @param payAmount 单次支付金额
     * @return 修改结果
     */
    @Override
    public Wrapper<Void> updateProductPayAmount(OrderDO order, BigDecimal payAmount) {
        if(payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.success();
        }

        List<OrderProductDO> products = orderProductRepository.findByOrder(order);
        if(CollectionUtils.isEmpty(products)) {
            return Wrapper.success();
        }

        //根据商品总价加权平均
        Map<Long, BigDecimal> map = weightedPayAmount(products, payAmount);
        products.forEach(product -> product.setPaidAmount(map.getOrDefault(product.getId(), BigDecimal.ZERO)));
        orderProductRepository.saveAll(products);
        return Wrapper.success();
    }

    /**
     * （转单）根据订单中的上游供应商与供应商商品，查询上游供应商商品信息
     *
     * @param roleId        当前供应商要转单的服务消费者角色Id
     * @param orders        订单列表
     * @param orderProducts 订单商品列表
     * @return 上游供应商商品列表
     */
    @Override
    public Wrapper<List<SupplyProductDTO>> findSupplyProducts(Long roleId, List<OrderDO> orders, List<OrderProductDO> orderProducts) {
        //转单后订单的单价：
        // 1.当前的销售订单的下单模式是进货单下单，且商品上上游供应会员商品的商品定价为现货价格，则取商品上上游供应会员商品的单价
        // 2.当前的销售订单的下单模式是询报价下单，且商品上上游供应会员商品的商品定价为价格需要询价，且销售订单的商品有二次询价，则取销售订单上对应询报价单的二次询价单中商品的报价单价（转单后的采购订单下单模式是询报价下单，对应报价单为二次询价的询价单号）
        // 3.当前的销售订单的下单模式是询报价下单，且商品上上游供应会员商品的商品定价为价格需要询价，且销售订单的商品没有二次询价，则提示[勾选的销售订单中，有需要询价的商品，无法进行转单。]

        //构造接口参数，从商品服务查询上游供应商商品信息
        List<VendorProductBO> vendorProducts = orders.stream().map(order -> {
            VendorProductBO vendorProduct = new VendorProductBO();
            vendorProduct.setVendorMemberId(order.getVendorMemberId());
            vendorProduct.setVendorRoleId(order.getVendorRoleId());
            vendorProduct.setProducts(orderProducts.stream().filter(orderProduct -> orderProduct.getOrder().getId().equals(order.getId())).map(orderProduct -> new OrderProductBO(orderProduct.getProductId(), orderProduct.getSkuId())).collect(Collectors.toList()));
            return vendorProduct;
        }).collect(Collectors.toList());

        Wrapper<List<SupplyProductDTO>> productResult = productFeignService.findSupplyProducts(roleId, vendorProducts);
        if(productResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(productResult.getCode(), productResult.getMessage());
        }

        //Step 1: 校验每个商品都是否存在上游供应商商品
        if(orderProducts.stream().anyMatch(orderProduct -> productResult.getData().stream().noneMatch(supplyProduct -> supplyProduct.getVendorSkuId().equals(orderProduct.getSkuId())))) {
            return Wrapper.fail(ResponseCode.ORDER_SUPPLY_PRODUCT_DOES_NOT_EXIST);
        }

        //Step 2: 查询配送方式为“自提”的地址，然后返回
        List<Long> addressIds = productResult.getData().stream().filter(p -> p.getDeliverType().equals(OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode()) && NumberUtil.notNullAndPositive(p.getAddressId())).map(SupplyProductDTO::getAddressId).collect(Collectors.toList());
        Wrapper<List<ProductAddressDTO>> addressResult = logisticsFeignService.findProductAddresses(addressIds);
        if(addressResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(addressResult.getCode(), addressResult.getMessage());
        }

        //Step 3: 查询并替换价格、自提地址等信息，然后返回
        productResult.getData().forEach(supplyProduct -> {
            orderProducts.stream().filter(p -> p.getSkuId().equals(supplyProduct.getVendorSkuId())).map(OrderProductDO::getQuantity).findFirst().ifPresent(quantity -> {
                supplyProduct.setPrice(findSupplyProductPrice(supplyProduct.getPrices(), quantity));
                supplyProduct.setQuantity(quantity);
            });

            addressResult.getData().stream().filter(address -> address.getAddressId().equals(supplyProduct.getAddressId())).findFirst().ifPresent(address -> {
                supplyProduct.setAddress(address.getAddress());
                supplyProduct.setReceiver(address.getReceiver());
                supplyProduct.setPhone(address.getPhone());
            });
        });

        return Wrapper.success(productResult.getData());
    }

    /**
     * （转单）检查订单发货条件，如果是转单订单发货，返回原订单及原订单的发货参数
     *
     * @param order      发货的订单
     * @param deliveryVO 发货接口参数
     * @return 检查结果
     */
    @Override
    public Wrapper<TransferOrderDeliveryBO> checkOrderDelivery(OrderDO order, VendorDeliveryVO deliveryVO) {
        //如果订单状态不为“待确认发货”，返回错误
        if(!order.getVendorInnerStatus().equals(VendorInnerStatusEnum.VENDOR_TO_CONFIRM_DELIVERY.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_HAS_COMPLETED);
        }

        if(order.getSeparateType().equals(OrderSeparateTypeEnum.DEFAULT.getCode())) {
            return Wrapper.success(new TransferOrderDeliveryBO(false));
        }

        //如果订单是“拼团订单”，拼团不成功时，不允许发货
        if(order.getOrderKind().equals(OrderSourceKindEnum.GROUP.getCode())) {
            if(order.getPromotionStatus().equals(OrderPromotionStatusEnum.GROUPING.getCode()) || order.getPromotionStatus().equals(OrderPromotionStatusEnum.GROUP_WAITING_CONFIRM.getCode())) {
                return Wrapper.fail(ResponseCode.ORDER_CAN_NOT_DELIVER_PRODUCTS_WHEN_GROUPING);
            }

            if(order.getPromotionStatus().equals(OrderPromotionStatusEnum.GROUP_FAILED.getCode())) {
                return Wrapper.fail(ResponseCode.ORDER_CAN_NOT_DELIVER_PRODUCTS_WHEN_GROUP_FAILED);
            }
        }

        //如果有转单订单，不允许发货
        if(order.getSeparateType().equals(OrderSeparateTypeEnum.SEPARATED.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_SEPARATED_ORDER_CAN_NOT_DELIVER_PRODUCT);
        }

        TransferOrderDeliveryBO deliveryBO = new TransferOrderDeliveryBO();
        //如果是转单后的订单，转单前的采购订单(下游采购商的采购订单)外部状态是否“待发货”
        if(order.getSeparateType().equals(OrderSeparateTypeEnum.TRANSFERRED.getCode()) && NumberUtil.notNullAndPositive(order.getRelationId())) {
            OrderDO seperateOrder = orderRepository.findById(order.getRelationId()).orElse(null);
            if(seperateOrder == null) {
                return Wrapper.fail(ResponseCode.ORDER_SEPARATED_ORDER_DOES_NOT_EXIST);
            }

            if(!seperateOrder.getVendorInnerStatus().equals(VendorInnerStatusEnum.VENDOR_TO_CONFIRM_DELIVERY.getCode())) {
                return Wrapper.fail(ResponseCode.ORDER_SEPARATED_ORDER_MUST_TO_DELIVERY);
            }

            deliveryBO.setDeliverSeparatedOrder(true);
            if(Objects.nonNull(deliveryVO)) {
                //判断接口参数中的relationId字段，要大于0
                if(deliveryVO.getProducts().stream().anyMatch(p -> NumberUtil.isNullOrZero(p.getRelationId()))) {
                    return Wrapper.fail(ResponseCode.ORDER_SEPARATED_PRODUCT_DOES_NOT_EXIST);
                }

                deliveryBO.setOrder(seperateOrder);

                //从当前订单的发货参数，构造转单前订单的发货参数
                VendorDeliveryVO separateOrderVeliveryVO = new VendorDeliveryVO();
                separateOrderVeliveryVO.setOrderId(seperateOrder.getId());
                separateOrderVeliveryVO.setDeliveryTime(StringUtils.hasLength(deliveryVO.getDeliveryTime()) ? deliveryVO.getDeliveryTime() : LocalDateTime.now().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
                separateOrderVeliveryVO.setAddress(StringUtils.hasLength(deliveryVO.getAddress()) ? deliveryVO.getAddress() : "");
                separateOrderVeliveryVO.setCompany(StringUtils.hasLength(deliveryVO.getCompany()) ? deliveryVO.getCompany() : "");
                separateOrderVeliveryVO.setLogisticsNo(StringUtils.hasLength(deliveryVO.getLogisticsNo()) ? deliveryVO.getLogisticsNo() : "");

                separateOrderVeliveryVO.setProducts(deliveryVO.getProducts().stream().map(product -> {
                    VendorToDeliveryProductVO productVO = new VendorToDeliveryProductVO();
                    productVO.setOrderProductId(product.getRelationId());
                    productVO.setDeliveryCount(product.getDeliveryCount());
                    productVO.setRelationId(0L);
                    return productVO;
                }).collect(Collectors.toList()));

                deliveryBO.setDeliveryVO(separateOrderVeliveryVO);
            }
        }

        return Wrapper.success(deliveryBO);
    }

    /**
     * （转单）检查订单收货条件，如果有转单订单，返回转单订单
     *
     * @param order 收货的订单
     * @return 检查结果
     */
    @Override
    public Wrapper<TransferOrderReceiveBO> checkOrderReceive(OrderDO order) {
        if(order.getSeparateType().equals(OrderSeparateTypeEnum.DEFAULT.getCode())) {
            return Wrapper.success(new TransferOrderReceiveBO(false));
        }

        //如果当前订单是转单后的订单，不允许收货
        if(order.getSeparateType().equals(OrderSeparateTypeEnum.TRANSFERRED.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_TRANSFERRED_ORDER_CAN_NOT_RECEIVE_PRODUCT);
        }

        if(NumberUtil.isNullOrZero(order.getRelationId())) {
            return Wrapper.fail(ResponseCode.ORDER_TRANSFERRED_ORDER_DOES_NOT_EXIST);
        }

        OrderDO transferredOrder = orderRepository.findById(order.getRelationId()).orElse(null);
        if(transferredOrder == null) {
            return Wrapper.fail(ResponseCode.ORDER_TRANSFERRED_ORDER_DOES_NOT_EXIST);
        }

        return Wrapper.success(new TransferOrderReceiveBO(transferredOrder));
    }

    /**
     * 保存赠送优惠券信息
     * @param order 订单
     * @param orderProductVOList 订单商品信息
     * @param giveCouponDTOMap 赠送的优惠券
     */
    @Override
    public void addGiveCouponList(OrderDO order, List<MobileOrderProductVO> orderProductVOList, Map<Long, List<OrderGiveCouponDTO>> giveCouponDTOMap) {
        logger.info("对优惠券进行分组后的信息:{}",giveCouponDTOMap);
        for (MobileOrderProductVO orderProductVO : orderProductVOList) {
            Long skuId = orderProductVO.getSkuId();
            logger.info("对订单分组后skuId:{}",skuId);
            List<OrderGiveCouponDTO> giveCouponDTOList = giveCouponDTOMap.get(skuId);
            if(!CollectionUtils.isEmpty(giveCouponDTOList)){
                List<OrderGiveCouponDO> giveCouponDOList = giveCouponDTOList.stream().map(give -> {
                    OrderGiveCouponDO orderGiveCouponDO = new OrderGiveCouponDO();
                    orderGiveCouponDO.setOrder(order);
                    orderGiveCouponDO.setGiveId(give.getGiveId());
                    orderGiveCouponDO.setProductId(give.getProductId());
                    orderGiveCouponDO.setBrand(give.getBrand());
                    orderGiveCouponDO.setCategory(give.getCategory());
                    orderGiveCouponDO.setName(give.getName());
                    orderGiveCouponDO.setQuantity(give.getQuantity());
                    orderGiveCouponDO.setSkuId(give.getSkuId());
                    orderGiveCouponDO.setUnit(give.getUnit());
                    return orderGiveCouponDO;
                }).collect(Collectors.toList());
                orderGiveCouponRepository.saveAll(giveCouponDOList);
            }
        }
    }

    /**
     * 根据商品总价加权平均支付金额
     * @param products 订单商品列表
     * @param payAmount 支付金额
     * @return 加权平均结果，key为OrderProductDO的Id，value为加权平均结果
     */
    private Map<Long, BigDecimal> weightedPayAmount(List<OrderProductDO> products, BigDecimal payAmount) {
        Long maxId = products.stream().max(Comparator.comparingLong(OrderProductDO::getId)).map(OrderProductDO::getId).orElse(0L);
        BigDecimal totalAmount = products.stream().map(OrderProductDO::getAmount).reduce(BigDecimal::add).orElse(BigDecimal.ONE);
        Map<Long, BigDecimal> map = products.stream().filter(p -> p.getId().compareTo(maxId) < 0).collect(Collectors.toMap(OrderProductDO::getId, p -> payAmount.multiply(p.getAmount()).divide(totalAmount, 2, RoundingMode.HALF_UP)));
        map.put(maxId, payAmount.subtract(map.values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO)));
        return map;
    }

    /**
     * 加权平均金额（为避免小数误差，调用前注意要将所有的BigDecimal设置为统一精度）
     * @param baseMap 加权列表， key为标识id，value为基础金额
     * @param amount  要平均的总金额
     * @return 加权平均结果，key为baseMap的key，value为加权平均结果（精度为3）
     */
    private Map<Long, BigDecimal> weightedAmount(Map<Long, BigDecimal> baseMap, BigDecimal amount) {
        //如果baseMap为空Map，会返回 key=0, value=amount的 Map
        //如果baseMap只有一个元素，返回
        if(baseMap.size() == 1) {
            return baseMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, v -> amount.setScale(3, RoundingMode.HALF_UP)));
        }

        //先取出最大的Key，计算其他元素的加权平均值
        Long maxId = baseMap.keySet().stream().max(Comparator.comparingLong(a -> a)).orElse(0L);
        BigDecimal totalAmount = baseMap.values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ONE);
        Map<Long, BigDecimal> map = baseMap.entrySet().stream().filter(e -> e.getKey().compareTo(maxId) < 0).collect(Collectors.toMap(Map.Entry::getKey, v -> v.getValue().multiply(amount).divide(totalAmount, 3, RoundingMode.HALF_UP)));
        //最后再将最大的key的值，用amount参数减去其他key计算结果的和，这样就避免了四舍五入造成的误差
        map.put(maxId, amount.subtract(map.values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO)).setScale(3, RoundingMode.HALF_UP));
        return map;
    }

    /**
     * 校验商品单价（非到手价）
     * @param priceMap 从商品服务获取的商品价格
     * @param quantity 订单商品的订购数量
     * @param orderProductPrice 订单商品的价格
     * @return 校验结果
     */
    private Wrapper<Void> checkProductPrice(Map<String, Double> priceMap, BigDecimal quantity, BigDecimal orderProductPrice) {
        Wrapper<BigDecimal> priceResult = findProductPrice(priceMap, quantity);
        if(priceResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(priceResult.getCode(), priceResult.getMessage());
        }

        if(priceResult.getData().compareTo(orderProductPrice.setScale(3, RoundingMode.HALF_UP)) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_PRICE_IS_NOT_CORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 校验商品单价（非到手价）
     * @param priceMap 从商品服务获取的商品价格
     * @param quantity 订单商品的订购数量
     * @return 校验结果
     */
    private Wrapper<BigDecimal> findProductPrice(Map<String, Double> priceMap, BigDecimal quantity) {
        if(CollectionUtils.isEmpty(priceMap)) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
        }

        // 商品服务返回的阶梯价格中，如果key是“0-0”，表示没有阶梯价，否则要判断阶梯价
        if(priceMap.containsKey("0-0")) {
            return Wrapper.success(BigDecimal.valueOf(priceMap.get("0-0")).setScale(3, RoundingMode.HALF_UP));
        }

        // 商品服务返回的阶梯价格的格式为 {"1-5": 10, "7-8": 20}，表示如果购买1-5件商品，价格为10元，购买7-8件商品，价格为20元
        // 规则：
        // a. 其中key中购买数量可以为小数（保留3位小数）
        // b. 如上例，如果购买6件商品，要取key为"1-5"的价格，如果购买9件商品以上，要取key为"7-8"的价格，即：取阶梯价格购买数量小于当前购买数量的，其中购买数量为最大值的那一条数据
        Map.Entry<String, Double> entry = priceMap.entrySet().stream().filter(stringDoubleEntry -> {
            List<BigDecimal> keys = Arrays.stream(stringDoubleEntry.getKey().split("-")).map(BigDecimal::new).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
            return quantity.compareTo(keys.get(0)) >= 0 && quantity.compareTo(keys.get(1)) <= 0;
        }).findFirst().orElse(priceMap.entrySet().stream().filter(stringDoubleEntry -> {
            List<BigDecimal> keys = Arrays.stream(stringDoubleEntry.getKey().split("-")).map(BigDecimal::new).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
            return quantity.compareTo(keys.get(1)) >= 0;
        }).max((first, second) -> {
            BigDecimal maxOfFirst = Arrays.stream(first.getKey().split("-")).map(BigDecimal::new).max(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
            BigDecimal maxOfSecond = Arrays.stream(second.getKey().split("-")).map(BigDecimal::new).max(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
            return maxOfFirst.compareTo(maxOfSecond);
        }).orElse(null));

        if(entry == null) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_PRICE_IS_NOT_CORRECT);
        }

        return Wrapper.success(BigDecimal.valueOf(entry.getValue()).setScale(3, RoundingMode.HALF_UP));
    }

    /**
     * 从商品服务返回的上游供应商商品列表中，查询上游供应商商品价格
     * @param priceMap 从商品服务获取的商品价格
     * @param quantity 订单商品的订购数量
     * @return 校验结果
     */
    private BigDecimal findSupplyProductPrice(Map<String, Double> priceMap, BigDecimal quantity) {
        if(CollectionUtils.isEmpty(priceMap) || quantity.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }

        // 商品服务返回的阶梯价格中，如果key是“0-0”，表示没有阶梯价，否则要判断阶梯价
        if(priceMap.containsKey("0-0")) {
            return BigDecimal.valueOf(priceMap.get("0-0")).setScale(3, RoundingMode.HALF_UP);
        }

        // 商品服务返回的阶梯价格的格式为 {"1-5": 10, "7-8": 20}，表示如果购买1-5件商品，价格为10元，购买7-8件商品，价格为20元
        // 规则：
        // a. 其中key中购买数量可以为小数（保留3位小数）
        // b. 如上例，如果购买6件商品，要取key为"1-5"的价格，如果购买9件商品以上，要取key为"7-8"的价格，即：取阶梯价格购买数量小于当前购买数量的，其中购买数量为最大值的那一条数据
        Map.Entry<String, Double> entry = priceMap.entrySet().stream().filter(stringDoubleEntry -> {
            List<BigDecimal> keys = Arrays.stream(stringDoubleEntry.getKey().split("-")).map(BigDecimal::new).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
            return quantity.compareTo(keys.get(0)) >= 0 && quantity.compareTo(keys.get(1)) <= 0;
        }).findFirst().orElse(priceMap.entrySet().stream().filter(stringDoubleEntry -> {
            List<BigDecimal> keys = Arrays.stream(stringDoubleEntry.getKey().split("-")).map(BigDecimal::new).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
            return quantity.compareTo(keys.get(1)) >= 0;
        }).max((first, second) -> {
            BigDecimal maxOfFirst = Arrays.stream(first.getKey().split("-")).map(BigDecimal::new).max(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
            BigDecimal maxOfSecond = Arrays.stream(second.getKey().split("-")).map(BigDecimal::new).max(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
            return maxOfFirst.compareTo(maxOfSecond);
        }).orElse(null));

        return entry == null ? BigDecimal.ZERO : BigDecimal.valueOf(entry.getValue()).setScale(3, RoundingMode.HALF_UP);
    }
}
